React hooks 的奇怪行为:延迟数据更新

IT技术 javascript reactjs react-hooks
2021-03-30 14:13:00

奇怪的行为:我希望第一个和第二个 console.log 显示不同的结果,但它们显示相同的结果,并且仅在下次单击时更改值。我应该如何编辑我的代码以使值不同?

function App() {
  const [count, setCount] = React.useState(false);
  const test = () => {
    console.log(count); //false
    setCount(!count);
    console.log(count); //false
  };
  return (
    <div className="App">
      <h1 onClick={test}>Hello StackOverflow</h1>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>

你可以在这里看到一个工作示例:https : //codesandbox.io/s/wz9y5lqyzk

3个回答

状态更新是异步的,因此如果您使用 Hooks,您可以useEffect在更新后收到通知。

下面是一个例子:

https://codesandbox.io/s/wxy342m6l

如果您使用的是 React 组件的 setState,则可以使用回调

this.setState((state) => ({count: !state.count}), () => console.log('Updated', this.state.count));

如果您需要状态值,请记住使用回调来更新状态。

状态更新是异步的setCount您从中获得函数useState无法神奇地伸出并更改count常量的值一方面,它是一个常数。另一方面,setCount无法访问它。相反,当您调用 时setCount,您的组件函数将再次被调用,并useState返回更新后的计数。

现场示例:

如果您需要在count更改时执行一些副作用,请使用useEffect

useEffect(() => {
  console.log(`count changed to ${count}`);
}, [count]);

请注意,我们告诉useEffect仅在count更改时调用我们的回调,这样如果我们有其他状态,我们的回调就不会不必要地运行。

现场示例:

setState钩不直接更新在组件的值。它更新它的内部状态,导致组件的重新渲染,然后返回您分配给的新状态值count

当您console.log(count)进入 时test,您会显示 的当前值count,即旧值(更新前)。如果您将 移动console.log()到渲染,您将看到新值:

const { useState } = React;

const Component = () => {
  const [count, setCount] = useState(false);

  const test = () => {
    console.log('before: ', count);
    setCount(!count)
  }
  
  console.log('after: ', count);

  return (
    <div className="App">
      <button onClick={test}>Click</button>
    </div>
  );
}

ReactDOM.render(
   <Component />,
   demo
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="demo"></div>