文档侦听器表现出异常行为

我有一个带有 onClick 函数的按钮,该函数会增加状态变量。我正在尝试添加一个事件侦听器,以便当用户按下回车键时,它会遵循完全相同的行为。然而,可以观察到,当用户按下回车键时,似乎多次调用该函数,而不是仅仅一次。我怎样才能解决这个问题?

https://codesandbox.io/s/friendly-gould-bpr7j

const { useState, useEffect } = React;


/*export default*/ function App() {

  const [value, updateValue] = useState(0);


  useEffect(() => {

    document.addEventListener("keypress", e => handleKeyPress(e));

  }, []);


  const onSubmit = () => {

    console.log(value);

    updateValue(oldVal => (oldVal + 1) % 2);

  };


  const handleKeyPress = e => {

    if (e.key === "Enter") {

      onSubmit();

    }

  };


  return <button onClick={() => onSubmit()}>Click me</button>;

}


ReactDOM.render(<App />, document.getElementById("root"));

<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>


萧十郎
浏览 77回答 0
0回答

慕桂英3389331

问题是你useEffect只能看到 的第一个版本handleKeyPress,它只能看到 的第一个版本onSubmit,它只能看到 的第一个版本value。相反,您的按钮将当前版本的onSubmit附加到其单击处理程序,因此它看到的是当前值value,而不是过时的值。由于onSubmit使用状态信息 ( value) 并handleKeyPress使用onSubmit,一种解决方案是将handleKeyPress依赖项添加到useEffect代码中并使用useEffect清理回调来更新handleKeyPress正在使用的信息:useEffect(() => {  document.addEventListener("keypress", handleKeyPress); // No need for the arrow function here, and...  return () => {      document.removeEventListener("keypress", handleKeyPress); // ...not using one simplifies this  };}, [handleKeyPress]);您还需要将其移至创建函数的位置下方:const { useState, useEffect } = React;/*export default*/ function App() {  const [value, updateValue] = useState(0);  const onSubmit = () => {    console.log(value);    updateValue(oldVal => (oldVal + 1) % 2);  };  const handleKeyPress = e => {    if (e.key === "Enter") {      onSubmit();    }  };  useEffect(() => {    document.addEventListener("keypress", handleKeyPress); // No need for the arrow function here, and...    return () => {        document.removeEventListener("keypress", handleKeyPress); // ...not using one simplifies this    };  }, [handleKeyPress]);  return <button onClick={() => onSubmit()}>Click me</button>;}ReactDOM.render(<App />, document.getElementById("root"));<div id="root"></div><script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>但是您可以通过将其移出状态设置器回调来onSubmit完全不依赖状态信息:console.logconst { useState, useEffect } = React;/*export default*/ function App() {  const [value, updateValue] = useState(0);  useEffect(() => {    document.addEventListener("keypress", handleKeyPress);    return () => {      document.removeEventListener("keypress", handleKeyPress);    };  }, []);  const onSubmit = () => {    updateValue(oldVal => {      console.log(oldVal);      return (oldVal + 1) % 2;    });  };  const handleKeyPress = e => {    if (e.key === "Enter") {      onSubmit();    }  };  return <button onClick={() => onSubmit()}>Click me</button>;}ReactDOM.render(<App />, document.getElementById("root"));<div id="root"></div><script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>handleKeyPress那么只连接旧版本就可以了。请注意,您仍然希望在卸载组件时将其删除。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Html5