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

时间:2019-08-31 05:59:30

标签: reactjs immutability react-hooks keydown

请查看此代码段。

function App() {
  useEffect(() => {
    document.addEventListener('keydown', onKeyDown);
  }, []);

  const onKeyDown = e => {
    setKeyMap({ ...keyMap, [e.keyCode]: true });
  };

  const [keyMap, setKeyMap] = useState({});

  // JSON.stringify gives only one kay-value pair
  return (
    <div className="App">
      <h1>Hello {JSON.stringify(keyMap)}</h1>
    </div>
  );
}

因此,我使用useEffect仅向keydown事件添加一个事件监听器。显然,这与componentDidMount相似,因为它仅发生一次。

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

所以说我按“ a”,那么我的keyMap应该看起来像这样:

{
    "65": true
}

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

{
    "65": true,
    "66": true
}

但这是怎么回事:

{
    "66": true
}

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

2 个答案:

答案 0 :(得分:2)

useEffect(() => {
    document.addEventListener('keydown', onKeyDown);
}, []);

由于将空数组作为第二个参数,因此在首次渲染组件时,该参数仅运行一次。 onKeyDown函数引用了当时的状态 ,因此keyMap中的setKeyMap({ ...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

2)或者,使用setKeyMap的功能版本。它将为您传递状态的最新值。

const onKeyDown = e => {
  setKeyMap(prevKeyMap => ({ ...prevKeyMap, [e.keyCode]: true }));
};

答案 1 :(得分:2)

您只需要将onKeyDown函数移动到useEffect挂钩中,就像这样。注意,我已经在useEffect挂钩的依赖项数组中添加了keyMap

https://codesandbox.io/s/red-sun-23bmu?fontsize=14