Sorry about another one of these but I’m at a loss. I am adding an event listener inside of useEffect()
. The event fires (console.log()
prints as expected) but the state isn’t getting updated. Could someone please explain to me what’s going on here and how to solve this problem? Thanks!
const [loading, setLoading] = useState({ message: "", progress: 0 });
useEffect(() => {
function handleProgress(e: ProgressEvent<EventTarget>) {
console.log(e.loaded);
setLoading({message: "Processing Data", progress: e.loaded});
}
document.addEventListener("progress", handleProgress);
return () => {
document.removeEventListener("progress", handleProgress);
};
}, []);
2
Answers
State behaves like snapshot. The set function only updates the state variable for the next render. If you read the state variable after calling the set function, you will still get the old value that was on the screen before your call.
you may check it using html like
<span>{loading}</span>
.Ref: React useState documentation
React state Snapshot documenation
The reason for this behavior is that the event listener function
handleProgress
captures the initial state of loading when it is defined. Therefore, whensetLoading
is called insidehandleProgress
, it is using the initial state and not the updated state.To solve this problem, you can utilize the functional form of
setLoading
provided by React’suseState
hook. This form ofsetLoading
allows you to update the state based on the previous state.Here is the code to correctly update the state based on the previous state: