我似乎无法解决 React 中过时的状态问题,因为它与事件处理程序和钩子有关。我从概念上理解发生了什么 - 有一个闭包捕获状态值的起始值,并且在我期望的时候没有更新。
我正在创建一个 NavBar 组件,我想在该组件上添加键盘控件以允许访问子菜单等。我将展示代码,然后描述正在发生/未发生的事情。我还将链接到一个代码沙盒,以便于分叉和调试。
导航栏
const NavBar: React.FC<Props> = ({ children, label }) => {
const {
actions: { createNavItemRef },
state: { activeSubMenuIndex, navBarRef },
} = useNav();
console.log('NAV.BAR', { activeSubMenuIndex });
return (
<nav aria-label={label} ref={navBarRef}>
<NavList aria-label={label} role="menubar">
{children} // NavItems
</NavList>
</nav>
);
};
导航项
const NavItem: React.FC<Props> = ({ children, hasSubMenu, to }) => {
const ChildrenArray = React.Children.toArray(children);
const {
actions: { handleSelectSubMenu },
state: { activeSubMenuIndex },
} = useNav();
const handleSubMenuToggle = () => {
handleSelectSubMenu(index);
};
return (
<li ref={ref} role="none">
<>
<ParentButton
aria-expanded={activeSubMenuIndex === index}
aria-haspopup="true"
onClick={handleSubMenuToggle}
role="menuitem"
tabIndex={index === 0 ? 0 : -1}
>
{ChildrenArray.shift()}
</ParentButton>
{ChildrenArray.pop()}
</>
</li>
);
};
使用导航
function useNav() {
const navBarRef = useRef<HTMLUListElement>(null);
const [activeSubMenuIndex, setActiveSubMenuIndex] = useState<number | undefined>();
const handleSelectSubMenu = (index?: number) => {
if (!index || activeSubMenuIndex === index) {
setActiveSubMenuIndex(undefined);
} else {
setActiveSubMenuIndex(index);
}
};
useEffect(() => {
const navbar = navBarRef?.current;
navbar?.addEventListener('keydown', () => {
console.log("UseNav", { activeSubMenuIndex });
});
// return () => remove event listener
}, [navBarRef, activeSubMenuIndex]);
return {
actions: {
createNavItemRef,
handleSelectSubMenu,
},
state: {
activeSubMenuIndex,
navBarRef,
},
};
}
这是我设置的精简版。最终,这就是正在发生的事情。
期待
我点击第一个 NavItem
并且它变成焦点。我按了一个箭头键(例如),日志 UseNav { activeSubMenuIndex })
以 undefined
正确注销。
然后我单击包含子菜单的 NavItem。 activeSubMenuIndex
更新并在 NavItem
中显示正确的子菜单(基于 activeSubMenuIndex === index
条件)。
但是,我希望 NavBar { activeSubMenuIndex })
在单击此 NavItem 时也能注销。但它没有。
在子菜单可见的情况下,我按下另一个箭头键,当 UseNav
日志显示时,我希望它包含正确的 activeSubMenuIndex
值,但它仍然是 undefined
.
最终,我需要在 NavBar 上为 keyPress
添加事件监听器,以便在整个过程中分配键盘导航。但是,如果我什至无法在这个 MVP 级别上正确更新状态值,那么如果不让它在以后使用和调试变得更加麻烦,我就无法真正向前推进。
我知道这是一个陈旧状态的问题,但我找不到任何关于这个主题的好文章,而不仅仅是在同一文件中增加一个数字。因此,任何有助于最终突破这堵墙的帮助都将是惊人的。
谢谢!
答案 0 :(得分:0)
看起来这个问题源于 useNav()
钩子的使用。当我在 NavBar
内部调用这个钩子时,引用和值被实例化一次。当我在 NavItem
中再次调用钩子时,这些相同的引用和值将再次实例化。
在这种情况下,与其使用钩子,不如将其包装在上下文中,以便将逻辑与 UI 隔离开来,但使组件在其数据源中保持一致。