Strange behavior of React hooks: delayed data update

前端 未结 3 646
走了就别回头了
走了就别回头了 2020-12-10 18:42

Strange behavior: I expect that the first and the second console.log display a different result, but they display the same result and the value is changed only on the next c

相关标签:
3条回答
  • 2020-12-10 18:59

    The setState hook doesn't update the value in the component directly. It updates it's internal state, causes a rerender of the component, and then returns the new state value, which you assign to count.

    When you console.log(count) inside test, you display the current value of count, which is the old value (before the update). If you'll move the console.log() to the render, you'll see the new value:

    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>

    0 讨论(0)
  • 2020-12-10 19:00

    The state update is asynchronous so if you are using Hooks you can use useEffect to be notified after an update.

    Here is an example:

    https://codesandbox.io/s/wxy342m6l

    If you are using setState of a React component, you can use the callback

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

    Remember to use the callback to update state if you need a state value.

    0 讨论(0)
  • 2020-12-10 19:15

    State updates are asynchronous. The setCount function you get from useState can't magically reach out and change the value of your count constant. For one thing, it's a constant. For another, setCount doesn't have access to it. Instead, when you call setCount, your component function will get called again, and useState will return the updated count.

    Live Example:

    const {useState} = React;
    
    function Example() {
      const [count, setCount] = useState(false);
      const test = () =>{
        setCount(!count); // Schedules asynchronous call to Example, re-rendering the component
      };
      return (
        <div className="App">
          <h1 onClick={test}>Hello CodeSandbox</h1>
          <div>Count: {String(count)}</div>
        </div>
      );
    }
    
    ReactDOM.render(<Example />, document.getElementById("root"));
    <div id="root"></div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>

    If you need to perform some side-effect when count changes, use useEffect:

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

    Notice that we tell useEffect to only call our callback when count changes, so that if we have other state, our callback doesn't run unnecessarily.

    Live Example:

    const {useState, useEffect} = React;
    
    function Example() {
      const [count, setCount] = useState(false);
      const test = () =>{
        setCount(!count); // Schedules asynchronous call to Example, re-rendering the component
      };
      useEffect(() => {
        console.log(`count changed to ${count}`);
      }, [count]);
      return (
        <div className="App">
          <h1 onClick={test}>Hello CodeSandbox</h1>
          <div>Count: {String(count)}</div>
        </div>
      );
    }
    
    ReactDOM.render(<Example />, document.getElementById("root"));
    <div id="root"></div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>

    0 讨论(0)
提交回复
热议问题