Browse Source

chore: optimize useModal performance - Do not trigger rerender of parent component (#28122)

pull/28161/head
Elaina Cherudim 4 years ago
committed by GitHub
parent
commit
52ceeafa7e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      components/_util/hooks/usePatchElement.tsx
  2. 96
      components/modal/useModal/index.tsx

4
components/_util/hooks/usePatchElement.tsx

@ -6,7 +6,7 @@ export default function usePatchElement(): [
] {
const [elements, setElements] = React.useState<React.ReactElement[]>([]);
function patchElement(element: React.ReactElement) {
const patchElement = React.useCallback((element: React.ReactElement) => {
// append a new element to elements (and create a new ref)
setElements(originElements => [...originElements, element]);
@ -15,7 +15,7 @@ export default function usePatchElement(): [
return () => {
setElements(originElements => originElements.filter(ele => ele !== element));
};
}
}, []);
return [elements, patchElement];
}

96
components/modal/useModal/index.tsx

@ -13,52 +13,78 @@ import {
let uuid = 0;
interface ElementsHolderRef {
patchElement: ReturnType<typeof usePatchElement>[1];
}
const ElementsHolder = React.memo(
React.forwardRef<ElementsHolderRef>((_props, ref) => {
const [elements, patchElement] = usePatchElement();
React.useImperativeHandle(
ref,
() => {
return {
patchElement,
};
},
[],
);
return <>{elements}</>;
}),
);
export default function useModal(): [Omit<ModalStaticFunctions, 'warn'>, React.ReactElement] {
const [elements, patchElement] = usePatchElement();
const holderRef = React.useRef<ElementsHolderRef>(null as any);
function getConfirmFunc(withFunc: (config: ModalFuncProps) => ModalFuncProps) {
return function hookConfirm(config: ModalFuncProps) {
uuid += 1;
const getConfirmFunc = React.useCallback(
(withFunc: (config: ModalFuncProps) => ModalFuncProps) => {
return function hookConfirm(config: ModalFuncProps) {
uuid += 1;
const modalRef = React.createRef<HookModalRef>();
const modalRef = React.createRef<HookModalRef>();
let closeFunc: Function;
const modal = (
<HookModal
key={`modal-${uuid}`}
config={withFunc(config)}
ref={modalRef}
afterClose={() => {
closeFunc();
}}
/>
);
let closeFunc: Function;
const modal = (
<HookModal
key={`modal-${uuid}`}
config={withFunc(config)}
ref={modalRef}
afterClose={() => {
closeFunc();
}}
/>
);
closeFunc = patchElement(modal);
closeFunc = holderRef.current?.patchElement(modal);
return {
destroy: () => {
if (modalRef.current) {
modalRef.current.destroy();
}
},
update: (newConfig: ModalFuncProps) => {
if (modalRef.current) {
modalRef.current.update(newConfig);
}
},
return {
destroy: () => {
if (modalRef.current) {
modalRef.current.destroy();
}
},
update: (newConfig: ModalFuncProps) => {
if (modalRef.current) {
modalRef.current.update(newConfig);
}
},
};
};
};
}
},
[],
);
return [
{
const fns = React.useMemo(
() => ({
info: getConfirmFunc(withInfo),
success: getConfirmFunc(withSuccess),
error: getConfirmFunc(withError),
warning: getConfirmFunc(withWarn),
confirm: getConfirmFunc(withConfirm),
},
<>{elements}</>,
];
}),
[],
);
// eslint-disable-next-line react/jsx-key
return [fns, <ElementsHolder ref={holderRef} />];
}

Loading…
Cancel
Save