Async Function In React Doesn't React To State Change
Solution 1:
State variables never change their values. (Note that you can, have, and should declare them with const
because they don't change).
Subsequent invokes of the component function will get a new state variable with the same name and a different value.
Your testFunction
function has closed over the old state variable.
I suspect you could solve this with a reference:
const [testVariable, setTestVariable] = useState(false);
const reference = useRef();
reference.current = testVariable;
… and then have your function test the value of reference.current
instead of testVariable
.
This does, however, feel like an XY Problem where the real solution is "Use the return value from the function you pass to useEffect
to stop whatever it is you want to stop" (and use testVariable
as a dependency of useEffect
).
Solution 2:
state update in react is async means that your state will be changed in next render cycle. you can useEffect hook to track if any state is changed or not.
useEffect(() => {
console.log(testVariable);
}, [testVariable]);
Solution 3:
Change it to
const [testVariable, setTestVariable] = useState(false);
useEffect(()=> {
testFunction();
}, [])
const testFunction = async () => {
awaittimeout(1000);
console.log("Setting test variable to: " + true);
let newTestVariable = true;
setTestVariable(newTestVariable);
awaittimeout(1000);
console.log("Test variable is: " + newTestVariable);
}
Changing the state variable is an asynchronous operation and works with something called the event loop. It will not immediately get updated when you did setTestVariable(true).
Solution 4:
The async function
is changing the state, but you're logging testVariable
in the same lifecycle, which is why it looks as though the state wasn't changed.
If you instead change the code to be
const [testVariable, setTestVariable] = React.useState(false)
console.log('testVariable', testVariable)
React.useEffect(() => {
testFunction()
}, [])
const testFunction = async () => {
awaittimeout(1000)
setTestVariable(!testVariable)
}
return<h2>{testVariable}</h2>
It will log the output:
testVariable false
testVariable false
testVariable true
testVariable true
The reason it's showing two logs for both false
and true
is because the console.log
is outside the React.useEffect(() => {}, [])
(which is equivalent to componentDidMount for stateful React components). React is first executing the console.log
before the component mounts, then after the component mounts it executes the code inside React.useEffect
and rerenders the component, thus executing the console.log
statement again.
To only log once you would have to change the React.useEffect
to:
React.useEffect(() => {
console.log('testVariable', testVariable)
testFunction()
}, [testVariable])
Adding a properties to the array arguments [testVariable]
, changes the React.useEffect
from being a componentDidMount
equivalent function to be a function chat executes on componentDidMount
and for every new state of testVariable
.
Post a Comment for "Async Function In React Doesn't React To State Change"