在 useEffect 内react setTimeout 和 setState

IT技术 javascript reactjs settimeout use-effect
2021-04-30 01:36:24

我有这个代码,我的问题是为什么在我的答案函数中我得到了初始状态。如何以正确的方式设置状态以在 setTimeout 函数的回调中获得正确的状态?

const App = () => {
  const [state, setState] = useState({
    name: "",
    password: "",
  });

  useEffect(() => {
    setState({ ...state, password: "hello" });
    setTimeout(answer, 1000);
  }, []);

  const answer = () => {
    console.log(state);
    // we get initial State
  };
  return <div className="App"></div>;
};
2个回答

原因是关闭。

answer功能将随时登录该值的statesetTimeout()功能关闭了,当它被调用。

在您的代码中,由于setTimeout()函数在state包含具有空值的对象时被调用,因此answer函数会记录该值,而不是记录更新后的值。

要记录状态的最新值,您可以使用useRef()钩子。这个钩子返回一个对象,其中包含一个名为的属性current,这个属性的值是传递给 的参数useRef()

function App() {
  const [state, setState] = React.useState({
    name: "",
    password: "",
  });

  const stateRef = React.useRef(state);

  React.useEffect(() => {
    stateRef.current = { ...stateRef.current, password: 'hello'};
    setState(stateRef.current);
    setTimeout(answer, 1000);
  }, []);

  const answer = () => {
    console.log(stateRef.current);
  };
  return <div></div>;
}

ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

该函数answer是除状态值之外的闭包,它在定义时捕获其作用域内的变量的值。当调用 useEffect 内部的回调时,它得到的 answer 方法会在 setState 之前的状态值上关闭。

这就是您将与之调用的函数,setTimeout因此即使超时,状态的旧值也会延迟。