使用自定义 Hook 事件处理反应陈旧状态
Posted
技术标签:
【中文标题】使用自定义 Hook 事件处理反应陈旧状态【英文标题】:React Stale State with Custom Hook Event Handling 【发布时间】:2021-06-24 17:55:07 【问题描述】:我似乎无法理解 React 中的陈旧状态问题,因为它与事件处理程序和钩子有关。我从概念上理解正在发生的事情 - 有一个闭包正在捕获状态值的起始值,并且没有在我期望的时候更新。
我正在创建一个 NavBar 组件,我想在该组件上添加键盘控件以允许访问子菜单等。我将展示代码,然后描述正在发生/未发生的事情。我还将链接到一个代码框,以便于分叉和调试。
CodeSandbox
导航栏
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
添加EventListeners,以便在整个过程中分配键盘导航。但是,如果我什至无法在这个 MVP 级别正确更新状态值,那么如果不让以后的工作和调试变得更加麻烦,我就无法真正前进。
我知道这是一个过时状态的问题,但我找不到任何关于这个主题的好文章,而不仅仅是在同一个文件中增加一个数字。因此,任何有助于最终突破这堵墙的帮助都将是惊人的。
谢谢!
【问题讨论】:
【参考方案1】:看起来这个问题源于使用了useNav()
钩子。当我在NavBar
内部调用这个钩子时,引用和值被实例化一次。当我在NavItem
中再次调用钩子时,这些相同的引用和值将再次实例化。
在这种情况下,与其使用钩子,不如将其包装在上下文中更有意义,以便将逻辑与 UI 隔离开来,但保持组件在其数据源中的一致性。
【讨论】:
以上是关于使用自定义 Hook 事件处理反应陈旧状态的主要内容,如果未能解决你的问题,请参考以下文章
java自定义事件,线程a如何每一秒钟触发一个事件,然后另一个线程b监听之,并作出反应?