From 1771fcefdc050c92fb04a53ec3a33d68af1828ca Mon Sep 17 00:00:00 2001 From: JarvisArt <38420763+JarvisArt@users.noreply.github.com> Date: Tue, 22 Nov 2022 16:09:04 +0800 Subject: [PATCH] fix: react18 submenu flicker (#551) --- src/Menu.tsx | 75 ++++++++++++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/src/Menu.tsx b/src/Menu.tsx index 5b490b8e..8f9359d6 100644 --- a/src/Menu.tsx +++ b/src/Menu.tsx @@ -247,23 +247,6 @@ const Menu = React.forwardRef((props, ref) => { ); } - // ========================= Mode ========================= - const [mergedMode, mergedInlineCollapsed] = React.useMemo< - [MenuMode, boolean] - >(() => { - if ((mode === 'inline' || mode === 'vertical') && inlineCollapsed) { - return ['vertical', inlineCollapsed]; - } - return [mode, false]; - }, [mode, inlineCollapsed]); - - // ====================== Responsive ====================== - const [lastVisibleIndex, setLastVisibleIndex] = React.useState(0); - const allVisible = - lastVisibleIndex >= childList.length - 1 || - mergedMode !== 'horizontal' || - disabledOverflow; - // ========================= Open ========================= const [mergedOpenKeys, setMergedOpenKeys] = useMergedState(defaultOpenKeys, { value: openKeys, @@ -279,30 +262,52 @@ const Menu = React.forwardRef((props, ref) => { const [inlineCacheOpenKeys, setInlineCacheOpenKeys] = React.useState(mergedOpenKeys); - const isInlineMode = mergedMode === 'inline'; - const mountRef = React.useRef(false); - // Cache - React.useEffect(() => { - if (isInlineMode) { - setInlineCacheOpenKeys(mergedOpenKeys); + // ========================= Mode ========================= + const [mergedMode, mergedInlineCollapsed] = React.useMemo< + [MenuMode, boolean] + >(() => { + if ((mode === 'inline' || mode === 'vertical') && inlineCollapsed) { + return ['vertical', inlineCollapsed]; } - }, [mergedOpenKeys]); + return [mode, false]; + }, [mode, inlineCollapsed]); + + const isInlineMode = mergedMode === 'inline'; + + const [internalMode, setInternalMode] = React.useState(mergedMode); + const [internalInlineCollapsed, setInternalInlineCollapsed] = React.useState(mergedInlineCollapsed); - // Restore React.useEffect(() => { + setInternalMode(mergedMode); + setInternalInlineCollapsed(mergedInlineCollapsed) + if (!mountRef.current) { return; } - + // Synchronously update MergedOpenKeys if (isInlineMode) { setMergedOpenKeys(inlineCacheOpenKeys); } else { // Trigger open event in case its in control triggerOpenKeys(EMPTY_LIST); } - }, [isInlineMode]); + }, [mergedMode, mergedInlineCollapsed]); + + // ====================== Responsive ====================== + const [lastVisibleIndex, setLastVisibleIndex] = React.useState(0); + const allVisible = + lastVisibleIndex >= childList.length - 1 || + internalMode !== 'horizontal' || + disabledOverflow; + + // Cache + React.useEffect(() => { + if (isInlineMode) { + setInlineCacheOpenKeys(mergedOpenKeys); + } + }, [mergedOpenKeys]); React.useEffect(() => { mountRef.current = true; @@ -431,7 +436,7 @@ const Menu = React.forwardRef((props, ref) => { } // Whatever selectable, always close it - if (!multiple && mergedOpenKeys.length && mergedMode !== 'inline') { + if (!multiple && mergedOpenKeys.length && internalMode !== 'inline') { triggerOpenKeys(EMPTY_LIST); } }; @@ -450,7 +455,7 @@ const Menu = React.forwardRef((props, ref) => { if (open) { newOpenKeys.push(key); - } else if (mergedMode !== 'inline') { + } else if (internalMode !== 'inline') { // We need find all related popup to close const subPathKeys = getSubPathKeys(key); newOpenKeys = newOpenKeys.filter(k => !subPathKeys.has(k)); @@ -471,7 +476,7 @@ const Menu = React.forwardRef((props, ref) => { }; const onInternalKeyDown = useAccessibility( - mergedMode, + internalMode, mergedActiveKey, isRtl, uuid, @@ -504,7 +509,7 @@ const Menu = React.forwardRef((props, ref) => { // >>>>> Children const wrappedChildList = - mergedMode !== 'horizontal' || disabledOverflow + internalMode !== 'horizontal' || disabledOverflow ? childList : // Need wrap for overflow dropdown that do not response for open childList.map((child, index) => ( @@ -528,10 +533,10 @@ const Menu = React.forwardRef((props, ref) => { className={classNames( prefixCls, `${prefixCls}-root`, - `${prefixCls}-${mergedMode}`, + `${prefixCls}-${internalMode}`, className, { - [`${prefixCls}-inline-collapsed`]: mergedInlineCollapsed, + [`${prefixCls}-inline-collapsed`]: internalInlineCollapsed, [`${prefixCls}-rtl`]: isRtl, }, rootClassName, @@ -561,7 +566,7 @@ const Menu = React.forwardRef((props, ref) => { ); }} maxCount={ - mergedMode !== 'horizontal' || disabledOverflow + internalMode !== 'horizontal' || disabledOverflow ? Overflow.INVALIDATE : Overflow.RESPONSIVE } @@ -582,7 +587,7 @@ const Menu = React.forwardRef((props, ref) => {