Skip to content

Commit

Permalink
feat: [LazyComponent] export LazyComponentOnLoadParams
Browse files Browse the repository at this point in the history
  • Loading branch information
akai committed Mar 9, 2021
1 parent 524401d commit 3bfd3fe
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 22 deletions.
8 changes: 6 additions & 2 deletions src/components/LazyComponent/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import React from 'react';
import { SuspenseWrap } from './SuspenseWrap';
import { LazyComponentProps, LazyComponentPropsWithCode } from './interface';
import {
LazyComponentProps,
LazyComponentPropsWithCode,
LazyComponentOnLoadParams,
} from './interface';
import { useComponents } from '../ComponentsProvider/useComponents';

export type { LazyComponentProps };
export type { LazyComponentProps, LazyComponentOnLoadParams };

export const LazyComponentWithCode: React.FC<LazyComponentPropsWithCode> = (props) => {
const { code, fallback, onLoad, onError, ...rest } = props;
Expand Down
7 changes: 6 additions & 1 deletion src/components/LazyComponent/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ export interface LazyComponentPropsWithComponent extends LazyComponentBaseProps
component: React.ComponentType | null;
}

export interface LazyComponentOnLoadParams {
async: boolean;
component: React.ComponentType<any>;
}

export interface LazyComponentPropsWithCode extends LazyComponentBaseProps {
code: string;
onLoad?: (e: { async: boolean; component: React.ComponentType<any> }) => void;
onLoad?: (e: LazyComponentOnLoadParams) => void;
}

export type LazyComponentProps = LazyComponentPropsWithComponent | LazyComponentPropsWithCode;
4 changes: 1 addition & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@ export { importScript } from './utils/importScript';
export { lazyComponent } from './utils/lazyComponent';
export { mountComponent } from './utils/mountComponent';

/* eslint-disable import/no-cycle */
export { ComponentsProvider, useComponents } from './components/ComponentsProvider';
export type { ComponentsProviderProps, ComponentsMap } from './components/ComponentsProvider';

export { LazyComponent } from './components/LazyComponent';
export type { LazyComponentProps } from './components/LazyComponent';
/* eslint-enable import/no-cycle */
export type { LazyComponentProps, LazyComponentOnLoadParams } from './components/LazyComponent';

export { Avatar } from './components/Avatar';
export type { AvatarProps, AvatarSize, AvatarShape } from './components/Avatar';
Expand Down
175 changes: 159 additions & 16 deletions storybook/stories/ComponentProvider.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from 'react';
import React, { useEffect } from 'react';
import { Meta } from '@storybook/react/types-6-0';

import * as ChatUI from '../../src';
import { ComponentsMap } from '../../src';
import { ComponentsMap, LazyComponentOnLoadParams } from '../../src';

const { ComponentsProvider, LazyComponent } = ChatUI;
const { ComponentsProvider, LazyComponent, useComponents } = ChatUI;

export default {
title: 'ComponentsProvider',
Expand Down Expand Up @@ -89,24 +89,51 @@ export const LocalComponent = () => (
</ComponentsProvider>
);

function TestAsyncComponent() {
function LazySlot() {
const data = { list: [{ title: 'item-1' }, { title: 'item-2' }] };
return (
<div>
<h1>Example:</h1>
<LazyComponent
code="slot"
data={{ list: [{ title: 'item-1' }, { title: 'item-2' }] }}
meta={{}}
ctx={ctx}
onLoad={(a: any) => console.log('onLoad:', a)}
/>
</div>
<LazyComponent
code="slot"
data={data}
meta={{}}
ctx={ctx}
onLoad={(r: LazyComponentOnLoadParams) => console.log('slot - onLoad:', r)}
/>
);
}

function LazyRecommend() {
const data = {
recommends: [
{
knowledgeId: 'q1',
title: 'Question 1',
},
{
knowledgeId: 'q2',
title: 'Question 2',
},
{
knowledgeId: 'q3',
title: 'Question 3',
},
],
};
return (
<LazyComponent
code="recommend"
data={data}
meta={{}}
ctx={ctx}
onLoad={(r: any) => console.log('recommend - onLoad:', r)}
onError={(e: Error) => console.log('recommend - onError:', e)}
/>
);
}

export const AsyncComponent = () => (
<ComponentsProvider components={components}>
<TestAsyncComponent />
<LazySlot />
</ComponentsProvider>
);

Expand Down Expand Up @@ -141,7 +168,7 @@ function TestComponentHasError() {
code="slot"
onError={(err, errInfo) => {
setErrMsg(err.message);
console.log(errInfo);
console.log(222, err, errInfo);
}}
/>
{errMsg && <pre>Error message: {errMsg}</pre>}
Expand All @@ -164,6 +191,7 @@ function TestErrorUrl() {
code="error-url"
onError={(err) => {
setErrMsg(err.message);
console.log(222, err.message);
}}
/>
{errMsg && <pre>Error message: {errMsg}</pre>}
Expand Down Expand Up @@ -221,3 +249,118 @@ export const AsyncDecorator = () => (
<TestAsyncDecorator />
</ComponentsProvider>
);

function TestAddComponent() {
const { addComponent, hasComponent } = useComponents();
const forceUpdate = useForceUpdate();

function addRecommend() {
if (!hasComponent('recommend')) {
addComponent('recommend', {
name: 'AlimeComponentRecommend',
url: '//g.alicdn.com/alime-components/recommend/0.1.0/index.js',
});
// forceUpdate();
}
}

const onClick = React.useCallback(() => {
forceUpdate();
}, [forceUpdate]);

function handleImgLoad(e: any) {
console.log('img load', e);
}

return (
<div>
<img onLoad={handleImgLoad} src="11" alt="" />
<button type="button" onClick={onClick}>
update inner
</button>
<button onClick={addRecommend}>add recommend</button>
<LazyRecommend />
</div>
);
}

function useForceUpdate() {
const [, forceUpdate] = React.useState(false);

return React.useCallback(() => {
forceUpdate((s) => !s);
}, []);
}

export const AddComponent = () => {
const forceUpdate = useForceUpdate();
const renderCount = React.useRef(0);

React.useEffect(() => {
renderCount.current += 1;
});

const onClick = React.useCallback(() => {
forceUpdate();
}, [forceUpdate]);

return (
<div>
<button type="button" onClick={onClick}>
update
</button>
<div>Render count: {renderCount.current}</div>

<ComponentsProvider components={components}>
<TestAddComponent />
</ComponentsProvider>

<ComponentsProvider components={components}>
<LazySlot />
</ComponentsProvider>
</div>
);
};

export const MutableComponents = () => {
const [myComponents, setMyMyComponents] = React.useState({});
const forceUpdate = useForceUpdate();

function addSlot() {
setMyMyComponents({
...myComponents,
slot: {
name: 'AlimeComponentSlot',
url: '//g.alicdn.com/alime-components/slot/0.1.3/index.js',
},
});
}

function addRecommend() {
setMyMyComponents({
...myComponents,
recommend: {
name: 'AlimeComponentRecommend',
url: '//g.alicdn.com/alime-components/recommend/0.1.0/index.js',
},
});
}

const onClick = React.useCallback(() => {
forceUpdate();
}, [forceUpdate]);

return (
<div>
<button type="button" onClick={onClick}>
update
</button>
<button onClick={addSlot}>add slot</button>
<button onClick={addRecommend}>add recommend</button>
<ComponentsProvider components={myComponents}>
<LazySlot />
<LazyRecommend />
</ComponentsProvider>
</div>
);
};

0 comments on commit 3bfd3fe

Please sign in to comment.