fix: use a global cache for custom inputs so they can be accessed anywhere

This commit is contained in:
Josh 2022-12-02 17:23:00 +00:00
parent e3c273cf36
commit 38d13deafa
3 changed files with 46 additions and 11 deletions

View File

@ -9,6 +9,7 @@ import { Stack } from '@strapi/design-system/Stack';
import { useContentTypeLayout } from '../../hooks'; import { useContentTypeLayout } from '../../hooks';
import FieldComponent from '../FieldComponent'; import FieldComponent from '../FieldComponent';
import Inputs from '../Inputs'; import Inputs from '../Inputs';
import useLazyComponents from '../../hooks/useLazyComponents';
const NonRepeatableComponent = ({ componentUid, isFromDynamicZone, isNested, name }) => { const NonRepeatableComponent = ({ componentUid, isFromDynamicZone, isNested, name }) => {
const { getComponentLayout } = useContentTypeLayout(); const { getComponentLayout } = useContentTypeLayout();
@ -18,6 +19,8 @@ const NonRepeatableComponent = ({ componentUid, isFromDynamicZone, isNested, nam
); );
const fields = componentLayoutData.layouts.edit; const fields = componentLayoutData.layouts.edit;
const { lazyComponentStore } = useLazyComponents();
return ( return (
<Box <Box
background={isFromDynamicZone ? '' : 'neutral100'} background={isFromDynamicZone ? '' : 'neutral100'}
@ -67,6 +70,7 @@ const NonRepeatableComponent = ({ componentUid, isFromDynamicZone, isNested, nam
metadatas={metadatas} metadatas={metadatas}
queryInfos={queryInfos} queryInfos={queryInfos}
size={size} size={size}
customFieldInputs={lazyComponentStore}
/> />
</GridItem> </GridItem>
); );

View File

@ -21,6 +21,7 @@ import Preview from './Preview';
import DraggingSibling from './DraggingSibling'; import DraggingSibling from './DraggingSibling';
import { CustomIconButton } from './IconButtonCustoms'; import { CustomIconButton } from './IconButtonCustoms';
import { connect, select } from './utils'; import { connect, select } from './utils';
import useLazyComponents from '../../../hooks/useLazyComponents';
const DragButton = styled.span` const DragButton = styled.span`
display: flex; display: flex;
@ -177,6 +178,8 @@ const DraggedItem = ({
const accordionTitle = toString(displayedValue); const accordionTitle = toString(displayedValue);
const accordionHasError = hasErrors ? 'error' : undefined; const accordionHasError = hasErrors ? 'error' : undefined;
const { lazyComponentStore } = useLazyComponents();
return ( return (
<Box ref={refs ? refs.dropRef : null}> <Box ref={refs ? refs.dropRef : null}>
{isDragging && <Preview />} {isDragging && <Preview />}
@ -273,6 +276,7 @@ const DraggedItem = ({
// onBlur={hasErrors ? checkFormErrors : null} // onBlur={hasErrors ? checkFormErrors : null}
queryInfos={queryInfos} queryInfos={queryInfos}
size={size} size={size}
customFieldInputs={lazyComponentStore}
/> />
</GridItem> </GridItem>
); );

View File

@ -1,42 +1,69 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useCustomFields } from '@strapi/helper-plugin'; import { useCustomFields } from '@strapi/helper-plugin';
const componentStore = new Map();
/** /**
* @description * @description
* A hook to lazy load custom field components * A hook to lazy load custom field components
* @param {Array.<string>} componentUids - The uids to look up components * @param {Array.<string>} componentUids - The uids to look up components
* @returns object * @returns object
*/ */
const useLazyComponents = (componentUids) => { const useLazyComponents = (componentUids = []) => {
const [lazyComponentStore, setLazyComponentStore] = useState({}); const [lazyComponentStore, setLazyComponentStore] = useState({});
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const customFieldsRegistry = useCustomFields(); const customFieldsRegistry = useCustomFields();
useEffect(() => { useEffect(() => {
const setStore = (store) => {
setLazyComponentStore(store);
setLoading(false);
};
const populateStoreWithCache = () => {
const internalStore = {};
componentStore.forEach((comp, uid) => {
internalStore[uid] = comp;
});
setStore(internalStore);
};
const lazyLoadComponents = async (uids, components) => { const lazyLoadComponents = async (uids, components) => {
const modules = await Promise.all(components); const modules = await Promise.all(components);
const internalStore = {};
uids.forEach((uid, index) => { uids.forEach((uid, index) => {
if (!Object.keys(lazyComponentStore).includes(uid)) { componentStore.set(uid, modules[index].default);
setLazyComponentStore({ ...lazyComponentStore, [uid]: modules[index].default }); internalStore[uid] = modules[index].default;
}
}); });
setStore(internalStore);
}; };
if (componentUids.length) { if (componentUids.length) {
const componentPromises = componentUids.map((uid) => { /**
* These uids are not in the component store therefore we need to get the components
*/
const newUids = componentUids.filter((uid) => !componentStore.get(uid));
const componentPromises = newUids.map((uid) => {
const customField = customFieldsRegistry.get(uid); const customField = customFieldsRegistry.get(uid);
return customField.components.Input(); return customField.components.Input();
}); });
lazyLoadComponents(componentUids, componentPromises); if (componentPromises.length > 0) {
lazyLoadComponents(newUids, componentPromises);
} else {
populateStoreWithCache();
}
} else if (loading) {
populateStoreWithCache();
} }
}, [componentUids, customFieldsRegistry, loading]);
if (componentUids.length === Object.keys(lazyComponentStore).length) {
setLoading(false);
}
}, [componentUids, customFieldsRegistry, loading, lazyComponentStore]);
return { isLazyLoading: loading, lazyComponentStore }; return { isLazyLoading: loading, lazyComponentStore };
}; };