From a1ac5deae1a6c4ea72ee2ab86dcf45bf2ce68862 Mon Sep 17 00:00:00 2001 From: chad1008 <13856531+chad1008@users.noreply.github.com> Date: Wed, 22 Jun 2022 13:04:43 -0400 Subject: [PATCH] fix Controlled state by ensuring dependency Ref is kept in sync with state --- packages/components/src/navigation/index.js | 22 ++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/components/src/navigation/index.js b/packages/components/src/navigation/index.js index a1e1df9b2f41f..8a71ba753e402 100644 --- a/packages/components/src/navigation/index.js +++ b/packages/components/src/navigation/index.js @@ -6,7 +6,12 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { useEffect, useRef, useState } from '@wordpress/element'; +import { + useEffect, + useLayoutEffect, + useRef, + useState, +} from '@wordpress/element'; import { isRTL } from '@wordpress/i18n'; /** @@ -28,7 +33,6 @@ export default function Navigation( { onActivateMenu = noop, } ) { const [ menu, setMenu ] = useState( activeMenu ); - const menuRef = useRef( activeMenu ); const [ slideOrigin, setSlideOrigin ] = useState(); const navigationTree = useCreateNavigationTree(); const defaultSlideOrigin = isRTL() ? 'right' : 'left'; @@ -51,15 +55,15 @@ export default function Navigation( { } }, [] ); - useEffect( () => { - menuRef.current = menu; - }, [ menu ] ); + // Used to prevent excessive useEffect fires when navigation is being controlled by parent component + const controlledMenuUpdate = useRef( { setActiveMenu, menu } ); + useLayoutEffect( () => { + controlledMenuUpdate.current = { setActiveMenu, menu }; + } ); - // Used to prevent resetting the `menu` state when navigating between menus - const setActiveMenuRef = useRef( setActiveMenu ); useEffect( () => { - if ( activeMenu !== menuRef.current ) { - setActiveMenuRef.current( activeMenu ); + if ( activeMenu !== controlledMenuUpdate.current.menu ) { + controlledMenuUpdate.current.setActiveMenu( activeMenu ); } }, [ activeMenu ] );