请看一下这段代码片段。
function App() {
useEffect(() => {
document.addEventListener('keydown', onKeyDown);
}, []);
const onKeyDown = e => {
setKeyMap({ ...keyMap, [e.keyCode]: true });
};
const [keyMap, setKeyMap] = useState({});
// JSON.stringify gives only one key-value pair
return (
<div className="App">
<h1>Hello {JSON.stringify(keyMap)}</h1>
</div>
);
}
因此,使用useEffect
,我只向keydown
事件添加一个事件侦听器一次。这显然类似于 componentDidMount,因为这只发生一次。
在键关闭事件的事件处理程序中,我正在尝试添加所有按下为 true 的键码。
所以说我按"a",那么我的键盘映射应该看起来像这样:
{
"65": true
}
现在,如果我按"b",那么我的键盘映射应该看起来像这样:
{
"65": true,
"66": true
}
但正在发生的事情是这样的:
{
"66": true
}
为什么我无法改变以前的状态并添加它?就像我以前用"65"作为键一样,但是当我按键盘上的另一个键时,突然这个"65"键值消失了。也就是说,在任何给定点,由于某种原因,只有one
键值对存在。我希望能够根据需要多次添加到此对象(我的意思是keyMap对象(。...
运算符(点差(不工作吗?
useEffect(() => {
document.addEventListener('keydown', onKeyDown);
}, []);
由于空数组作为第二个参数,因此在组件首次呈现时,它只会运行一次。onKeyDown 函数引用当时的状态,因此setKeyMap({ ...keyMap, [e.keyCode]: true });
中的keyMap
引用空对象。每当调用此键处理程序时,它都会将状态设置为空对象以及最新的键。
相反,您希望它使用最新状态。您有两个主要选项来执行此操作
1(不要跳过效果。这样,您将始终拥有一个具有最新状态的事件侦听器。请记住返回一个拆解函数,这样您就不会有事件侦听器泄漏:
useEffect(() => {
const onKeyDown = e => {
setKeyMap({ ...keyMap, [e.keyCode]: true });
};
document.addEventListener('keydown', onKeyDown);
return () => document.removeEventListener('keydown', onKeyDown);
}); // You could also pass [keyMap] as the second param to skip irrelevant changes
2( 或者,使用 setKeyMap 的函数版本。它将传递状态的最新值。
const onKeyDown = e => {
setKeyMap(prevKeyMap => ({ ...prevKeyMap, [e.keyCode]: true }));
};
你只需要像这样将 onKeyDown 函数移动到 useEffect 钩子内部。注意我在依赖项数组中添加了 useEffect 钩子的keyMap
:
https://codesandbox.io/s/red-sun-23bmu?fontsize=14