From 52ceeafa7ece4aa05366abdb67f7bbf691ffcc41 Mon Sep 17 00:00:00 2001 From: Elaina Cherudim Date: Wed, 2 Dec 2020 20:00:31 +0800 Subject: [PATCH] chore: optimize useModal performance - Do not trigger rerender of parent component (#28122) --- components/_util/hooks/usePatchElement.tsx | 4 +- components/modal/useModal/index.tsx | 96 ++++++++++++++-------- 2 files changed, 63 insertions(+), 37 deletions(-) diff --git a/components/_util/hooks/usePatchElement.tsx b/components/_util/hooks/usePatchElement.tsx index 18c1645dd9..fb75f159ae 100644 --- a/components/_util/hooks/usePatchElement.tsx +++ b/components/_util/hooks/usePatchElement.tsx @@ -6,7 +6,7 @@ export default function usePatchElement(): [ ] { const [elements, setElements] = React.useState([]); - 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]; } diff --git a/components/modal/useModal/index.tsx b/components/modal/useModal/index.tsx index 73b62ff1e5..e98cacc0d8 100644 --- a/components/modal/useModal/index.tsx +++ b/components/modal/useModal/index.tsx @@ -13,52 +13,78 @@ import { let uuid = 0; +interface ElementsHolderRef { + patchElement: ReturnType[1]; +} + +const ElementsHolder = React.memo( + React.forwardRef((_props, ref) => { + const [elements, patchElement] = usePatchElement(); + React.useImperativeHandle( + ref, + () => { + return { + patchElement, + }; + }, + [], + ); + return <>{elements}; + }), +); + export default function useModal(): [Omit, React.ReactElement] { - const [elements, patchElement] = usePatchElement(); + const holderRef = React.useRef(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(); + const modalRef = React.createRef(); - let closeFunc: Function; - const modal = ( - { - closeFunc(); - }} - /> - ); + let closeFunc: Function; + const modal = ( + { + 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, ]; }