keycloak-demo-frontend/src/components/Base/Lazy/index.tsx

48 lines
1.5 KiB
TypeScript

import React, {
lazy, Suspense, useMemo, useState, useEffect,
} from 'react';
import cloneDeep from 'lodash/cloneDeep';
import Skeleton from '@material-ui/lab/Skeleton';
import Loading from '@Components/Base/Loading';
import { Props, ComponentState } from './types';
const Components: { [key: string]: ComponentState } = {};
const Lazy: React.FC<Props> = (props): React.ReactElement => {
const { componentImport, componentChunkName, componentProps } = props;
const [isRender, setIsRender] = useState(false);
const RenderComponent = useMemo(() => {
const Component = Components[componentChunkName];
if (Component) {
return <Component {...componentProps} />;
}
return (
<div style={{ width: '100%', height: '100%' }}>
<Loading typePosition="relative" typeZIndex={10005} typeIcon="line:fix" isLoading />
<Skeleton variant="rect" width="100%" height="100%" animation="wave" />
</div>
);
}, [componentChunkName, isRender, componentProps]);
/* Hooks */
useEffect(() => {
(async () => {
if (!Components[componentChunkName]) {
Components[componentChunkName] = lazy(async () => {
const Element = await componentImport;
return Element;
});
}
setIsRender(cloneDeep(!isRender));
})();
}, [componentChunkName]);
return (
<React.Fragment>
<Suspense fallback={<Loading typePosition="relative" typeZIndex={10005} typeIcon="line:fix" isLoading />}>
{RenderComponent}
</Suspense>
</React.Fragment>
);
};
export default Lazy;