I'm new to React and just practicing useEffect hooks after going through a hooks course.
I have a button to toggle state change of arrowState.
export default function Test() {
const [arrowState, setArrowState] = useState(true);
const [arrowChange, setArrowChange] = useState(false);
const toggleButton = () => {
return setArrowState((arrowState) => {
return !arrowState;
});
};
return (
<>
<div>
<button
type="button"
onClick={toggleButton}
>
Toggle Arrow
</button>
</div>
{arrowChange && <Notific />}
</>
);
}
Then I have a useEffect hook which changes state of arrowChange. Also have a timeout to change state of arrowChange to false - thereby auto-disappearing the button after 2 secs.
useEffect(() => {
console.log("first line of useEffect.arrowChange is ", arrowChange);
setArrowChange(true);
console.log(
"immediately after setArrowChange to true. arrowChange is ",
arrowChange
);
setTimeout(() => {
console.log("first line of setTimeOut. arrowChange is ", arrowChange);
arrowChange && setArrowChange(false);
}, 1000);
return () => {
console.log("cleaning up arrowchange. arrowChange is ", arrowChange);
setArrowChange(false);
};
}, [arrowState]);
Based on it, I'm displaying another button with a message.
function Notific() {
return (
<button
type="button"
onClick={() => setArrowChange(false)}
>
Arrow state has been changed
</button>
);
}
As you can see, I'm logging some messages to see the effect. I'm surprised to see that even after setting arrowChange to true at the beginning of useEffect hook, it's still showing false at alternate events.
Check these console logs:
cleaning up arrowchange. arrowChange is false
Test.js:57 first line of useEffect.arrowChange is true
Test.js:59 immediately after setArrowChange to true. arrowChange is true
Test.js:65 first line of setTimeOut. arrowChange is true
Test.js:70 cleaning up arrowchange. arrowChange is true
Test.js:57 first line of useEffect.arrowChange is false
Test.js:59 immediately after setArrowChange to true. arrowChange is false
Test.js:65 first line of setTimeOut. arrowChange is false
Test.js:70 cleaning up arrowchange. arrowChange is false
Test.js:57 first line of useEffect.arrowChange is true
Test.js:59 immediately after setArrowChange to true. arrowChange is true
Test.js:65 first line of setTimeOut. arrowChange is true
Test.js:70 cleaning up arrowchange. arrowChange is true
Test.js:57 first line of useEffect.arrowChange is false
Test.js:59 immediately after setArrowChange to true. arrowChange is false
Test.js:65 first line of setTimeOut. arrowChange is false
Test.js:70 cleaning up arrowchange. arrowChange is false
Test.js:57 first line of useEffect.arrowChange is true
Test.js:59 immediately after setArrowChange to true. arrowChange is true
Test.js:65 first line of setTimeOut. arrowChange is true
To understand the output of the code, you need to understand the fundamental concepts of how react updates the state and the concept of a closure.
Every call to state setter function such as setArrowChange is scheduled - state is not updated immediately.
As a result, logging the value of arrowChange immediately after calling setArrowChange will log the old value of arrowChange.
State is constant; this means that irrespective of how many times you call the state setter function, component can't see the updated state until it re-renders.
When you create a function is javascript, it forms a closure over its surrounding scope.
In your case, the callback function of setTimeout will log the value of arrowChange was in-effect when the callback function was created.
If at the time of setTimeout call, arrowChange is false, and before the timer expires, you update the state to true, the callback function will still log false because of the closure.
The cleanup function also has a closure over the arrowChange; it logs the value of arrowChange that was in-effect when the cleanup function was created and returned from the callback function of the useEffect hook.
Now let's take a look at the first group of console.log output.
cleaning up arrowchange. arrowChange is false Test.js:57 first line of useEffect.arrowChange is true Test.js:59 immediately after setArrowChange to true. arrowChange is true Test.js:65 first line of setTimeOut. arrowChange is true
First line of output
cleaning up arrowchange. arrowChange is false
is from the cleanup function of the useEffect hook that executes:
useEffect againAs explained above, it logs the value of the arrowChange which it closed over when the cleanup function of the useEffect was created. Output of the cleanup function suggests that:
arrowChange was false when the cleanup function was created and returned from the useEffect hook's callback functionarrowChange is false, so this output if from the cleanup function that was most likely created when the useEffect hook executed for the first time, after the initial render of the componentNext three lines
Test.js:57 first line of useEffect.arrowChange is true
Test.js:59 immediately after setArrowChange to true. arrowChange is true
Test.js:65 first line of setTimeOut. arrowChange is true
log the latest value of arrowChange which is most likely because of setArrowChange(true) call in the second line of the useEffect hook that executed after the initial render of the component.
If you observe the output of other groups of console.log outputs, you will notice that the value of arrowChange logged by the cleanup function is opposite to the value logged by the console.log statements inside the callback function of the useEffect hook.
The reason for this is that the cleanup function is from the previous execution of the useEffect hook and it logs the value of arrowChange that was in-effect during the previous execution of the useEffect hook.
console.log statements inside the callback function of the useEffect hook log the latest value of the arrowChange and in the next execution of the useEffect hook, this latest value will become the previous value and the opposite of this latest value will become the latest value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With