问题
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
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.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:
setColor
changes the state.- The change in stage makes the Function Component execute again
- The new invoke of the Function Component reruns
let [color, setColor] = useState("red");
- This assigns the current state of
color
to thecolor
variable. - Time passes
- The arrow function passed to
setTimeout
runs. This has closed over the previouscolor
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