简体   繁体   English

useEffect 中的状态随延迟变化

[英]State inside useEffect changing with delay

I'm trying to manipulate the DOM based on what's being typed ( text ) in an input in a React component:我正在尝试根据在 React 组件的输入中输入的内容( text )来操作 DOM:

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";

function App() {
  const [text, setText] = useState("Initial value");

  function handleChange(event) {
    setText(event.target.value);
  }

  useEffect(() => {
    function handleKeypress(event) {
      console.log("text", text);
      // do something with the DOM with text
    }

    document.addEventListener("keydown", handleKeypress);

    return () => {
      document.removeEventListener("keydown", handleKeypress);
    };
  }, [text]);

  return (
    <div id="keys">
      <input type="text" onChange={handleChange} value={text} />
    </div>
  );
}

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

It works, but something strange happens.它有效,但发生了一些奇怪的事情。 text won't change unless keydown is triggered a second time.除非第二次触发keydown ,否则text不会改变。

For example, if you press a , console.log("text", text) will log Initial value .例如,如果您按下aconsole.log("text", text)将记录Initial value It won't log a .它不会记录a . I think there's some kind of delay.我认为有某种延迟。

Why is this?为什么是这样? And how to change the code so that console.log("text", text) logs the key that's being pressed?以及如何更改代码以便console.log("text", text)记录正在按下的键?

Live code: https://codesandbox.io/s/react-hooks-useeffect-forked-sfujxi?file=/src/index.js实时代码: https ://codesandbox.io/s/react-hooks-useeffect-forked-sfujxi?file=/src/index.js

Note: The reason I'm using the event listener is that I want the code to also run when, for example, I press Ctrl + Key (in that situation text doesn't change).注意:我使用事件监听器的原因是我希望代码也能在我按下Ctrl + Key时运行(在这种情况下text不会改变)。

It seems that this is because the text state is updated in the next render of the component, but the event block is still using the old value before the update.看起来这是因为在组件的下一次渲染中更新了text状态,但是事件块仍在使用更新前的旧值。

Try not to use a event listener but let useEffect capture the change of the text state and it should log the correct input (when text changes):尽量不要使用事件侦听器,但让useEffect捕获text状态的更改,它应该记录正确的输入(当text更改时):

  useEffect(() => {
    console.log("text", text);
  }, [text]);

Alternatively if the goal is to log the key pressed, perhaps consider to just capture it with event since the event will have the value of the pressed key.或者,如果目标是记录按下的键,也许考虑只用event捕获它,因为event将具有按下的键的值。

There is no need to read from text state for this approach, instead perhaps consider to set the captured value as a state for display in some other components.这种方法不需要从text状态中读取,而是可以考虑将捕获的值设置为在其他一些组件中显示的状态。

  useEffect(() => {
    function handleKeypress(event) {
      console.log(event.keyCode);
    }
    document.addEventListener("keydown", handleKeypress);
    return () => {
      document.removeEventListener("keydown", handleKeypress);
    };
  }, []);

Considering the Note that you have provided in your question If you want the handleKeypress function to run when the user presses a key combination, such as Ctrl + Key , you can use the event.ctrlKey property to check if the Ctrl key is being pressed.考虑到您在问题中提供的注释如果您希望handleKeypress函数在用户按下组合键(例如Ctrl + Key )时运行,您可以使用event.ctrlKey属性检查是否按下了 Ctrl 键。

function handleKeypress(event) {
  if (event.ctrlKey) {
    console.log("Ctrl + Key was pressed");
  }
}

If you want to check for specific key combinations for example, to check for Ctrl + S you can do that using event.key property .例如,如果您想检查特定的组合键,要检查Ctrl + S ,您可以使用event.key property来做到这一点。

function handleKeypress(event) {
  if (event.ctrlKey && event.key === "s") {
    console.log("Ctrl + S was pressed");
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM