Callback doesn't receive the updated version of state even when it fires well after state changes

非 Y 不嫁゛ 提交于 2021-01-28 11:23:39

问题


I'm using a functional component. I'm aware setColor changes the value of color asynchronously. However, my callback function doesn't receive the updated version of color (blue) even when it executes well after color has been updated. Here's an abstract version of my code:

let [color, setColor] = useState("red");

useEffect(() => {
  setColor("blue");
  setTimeout(() => {
    console.log(color);
  }, 5000)
}, []);

(here's a sandbox: https://codesandbox.io/s/falling-cherry-17ip2?file=/src/App.js)

My only guess is that the setColor function almost creates a new color variable & console.log is stuck referencing the old color.


Troubleshooting

  1. I'm aware a secondary useEffect has the potential to execute my callback when state changes. However, this is inconvenient because I'm right in the middle of complex logic where I only want the callback to execute under certain conditions.

  2. I'm also aware useRef variables update pretty much immediately and so that'd be an alternative.


Nevertheless, the question still stands: why isn't the updated value of color being logged & is there anything I could do in the primary useEffect to access the latest version of color state?


回答1:


  1. setColor changes the state.
  2. The change in stage makes the Function Component execute again
  3. The new invoke of the Function Component reruns let [color, setColor] = useState("red");
  4. This assigns the current state of color to the color variable.
  5. Time passes
  6. The arrow function passed to setTimeout runs. This has closed over the previous color variable which was assigned the old state.



回答2:


Here is a snippet logging the color state value at various times and also showing the effect of cleaning up in the return of the useEffect. It only serves to illustrate the timeline that Quentin laid out in their answer.

const App = ()=>{
  const [color, setColor] = React.useState("red");
  
  console.log('outside: ', color);
  
  React.useEffect(() => {
    setColor("blue");
    console.log('inside: ', color);
    setTimeout(() => {
      console.log('inside-timed: ', color);
    }, 5000)
    
    // the cleaned-up timer won't fire
    const timer = setTimeout(() => {
      console.log('timer: ', color);
    }, 5000)

    return (clearTimeout(timer));
  },[])
  
 return (
  <div style={{backgroundColor: color, width: '40px', height: '40px'}} ></div>
 )
}

ReactDOM.render(
  <App />,
  document.getElementById("react")
);
<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>
<div id="react"></div>


来源:https://stackoverflow.com/questions/65220922/callback-doesnt-receive-the-updated-version-of-state-even-when-it-fires-well-af

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!