reactjs - React 钩子键盘导航
问题描述
我正在尝试使用 react-hooks 为列表实现键盘导航。
重要- 此列表可以根据搜索缩小/增长。
我的问题是围绕Enter
应该运行一些回调的键。activeCursor
不会改变,我理解因为它不在数组中,但是我怎样才能在不重新运行的情况下useEffect
获得当前状态?handleKeyPress
useEffect
此外,理想情况下,我希望useEffect
只在 mount ( []
) 上运行,但由于filteredMessages
更改我必须重新调用它,这也是我觉得奇怪的事情,因为它eventListeners
所以我什至不确定他们每次会发生什么......
const useKeyboardNavigation = (filteredMessages, onMessageSelection) => {
const [activeCursor, setActiveCursor] = React.useState(0);
const size = filteredMessages.length
const handleKeyPress = (event) => {
if (event.key === 'ArrowDown') {
setActiveCursor(prev => prev < size ? prev + 1 : 0)
}
else if (event.key === 'ArrowUp') {
setActiveCursor(prev => prev > 0 ? prev - 1 : size)
}
else if (event.key === 'Enter') {
const msg = filteredMessages[activeCursor] // ??? Always 0
onMessageSelection(msg)
}
};
React.useEffect(
() => {
// Each time the list changes I reset the cursor
setActiveCursor(0)
document.addEventListener('keydown', handleKeyPress);
return () => document.removeEventListener('keydown', handleKeyPress);
},
[filteredMessages]
);
return [activeCursor, setActiveCursor];
}
解决方案
打算发布我的解决方案,最终使用了状态和参考的混合。仍然愿意听取对大型列表具有更好性能的解决方案。
const useKeyboardNavigation = (size: number) => {
const [activeCursor, setActiveCursor] = React.useState(0);
const handleKeyPress = event => {
if (event.key === 'ArrowDown') {
setActiveCursor(prev => (prev < size ? prev + 1 : 0));
} else if (event.key === 'ArrowUp') {
setActiveCursor(prev => (prev > 0 ? prev - 1 : size));
}
};
// Reset when size changes
React.useEffect(() => setActiveCursor(0), [size]);
React.useEffect(
() => {
document.addEventListener('keydown', handleKeyPress);
return () => document.removeEventListener('keydown', handleKeyPress);
},
[size, activeCursor]
);
return [activeCursor, setActiveCursor];
};
用法:
const [activeCursor, setActiveCursor] = useKeyboardNavigation(messages.length);
然后当我渲染每个 ListItem (使用messages.map
):
const useFocus = (isActive: boolean) => {
const itemRef = React.useRef<HTMLDivElement>(null);
React.useEffect(
() => {
isActive && itemRef && itemRef.current && itemRef.current.focus();
},
[isActive]
);
return itemRef;
};
用法:
const myRef = useFocus(activeCursor === index);
<li ref={myRef} ...>
推荐阅读
- javascript - 解密带有错误的消息表单后端:BadPaddingException
- html - 使用网格我如何拥有文本和图像旁边的按钮
- javascript - 尝试在 ReactJS 中返回选择值
- python - 向数据框中添加一列,执行元素明智的操作
- r - 在 R 中是否可以在 ggplot + geom_sf 图表中包含组定义的圆圈?
- lua - 表成员函数是否允许没有参数?
- javascript - 在 vuex 中状态未定义的问题
- marklogic - 标记逻辑和查询
- haskell - Haskell:无法匹配预期类型
- numpy - 在 pytorch 数据加载器中从具有多个工作人员的 .npz 文件中读取密钥?