如何使用react hook useState添加到对象?

the*_*mer 5 immutability keydown reactjs react-hooks

请看一下这个代码片段。

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>
  );
}
Run Code Online (Sandbox Code Playgroud)

因此,使用useEffect,我keydown只向事件添加一次事件侦听器。这显然与 componentDidMount 类似,因为这只发生一次。

在 keydown 事件的事件处理程序中,我尝试添加所有被按下为 true 的键码。

假设我按“a”,那么我的 keyMap 应该如下所示:

{
    "65": true
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我按“b”,那么我的 keyMap 应该如下所示:

{
    "65": true,
    "66": true
}
Run Code Online (Sandbox Code Playgroud)

但发生的事情是这样的:

{
    "66": true
}
Run Code Online (Sandbox Code Playgroud)

为什么我无法改变以前的状态并添加到它?就像我以前有“65”作为键,但是当我按下键盘上的另一个键时,这个“65”键值突​​然消失了。也就是说,在任何给定点,one由于某种原因,只有键值对存在。我希望能够多次添加到这个对象(我的意思是 keyMap 对象)。运算...符(传播)不起作用吗?

Nic*_*wer 5

useEffect(() => {
    document.addEventListener('keydown', onKeyDown);
}, []);
Run Code Online (Sandbox Code Playgroud)

由于第二个参数为空数组,因此仅在组件首次渲染时运行一次。onKeyDown函数有一个对当时状态的引用,所以keyMapinsetKeyMap({ ...keyMap, [e.keyCode]: true });指的是一个空对象。每当调用此密钥处理程序时,它都会将状态设置为空对象,加上最新的密钥。

相反,您希望它使用最新状态。对于如何执行此操作,您有两个主要选项

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
Run Code Online (Sandbox Code Playgroud)

2)或者,使用setKeyMap的函数版本。它会向您传递该状态的最新值。

const onKeyDown = e => {
  setKeyMap(prevKeyMap => ({ ...prevKeyMap, [e.keyCode]: true }));
};
Run Code Online (Sandbox Code Playgroud)

  • 我也会使用第二个。但它只能工作,因为设置状态支持它。因此,如果您遇到类似的过时值问题但没有调用设置状态,您将需要了解第一个选项。 (2认同)