In Timer component, isSessionMode state which holds a boolean value is toggled conditionally in startTimer method (line: 40) as below.
setIsSessionMode((prev) => !prev);
But the state doesn’t seem to be updated because the logger in useEffect hook doesn’t print the state (line: 19) after setIsSessionMode() is called as below.
I think you are confusing setState and useState. The hook works differently than the class method. With the setter returned by useState (in this case setIsSessionMode) you just tell it what you want the new isSessionMode to be. If you are toggling, I would expect to see something like:
Again, I think you’re confusing setState with useState, What you are saying makes complete sense if we’re talking about setState. I have never heard of what you’re saying about a useState setter. I can’t find an example in the React docs.
You shouldn’t pass state updater function as a prop (e.g. setTimerLength from App to Timer). Create a separate function in App that calls state updater and pass it as a prop.
I notice that if I put a timer where the setIsSessionMode is being called, it is being re-called in a few milliseconds. Perhaps the component doesn’t rerender in time. I notice that when I do setIsSessionMode(!isSessionMode);, that it does rerender before it is toggled back. So, perhaps the callback function is taking long enough for the useEffect to not catch it.
But if you know that you want that effect to happen, why not just call a function that does what you want there instead of setting a flag that get’s listened for that my not fire off in time?
I also notice that as I run your stuff and put a log in the callback to setInterval, things are being called twice, almost like two intervals are being set. I haven’t been able to figure out why.
Looks like there is a note in React docs regarding state updating function (which I haven’t seen before ):
Note
React guarantees that setState function identity is stable and won’t change on re-renders. This is why it’s safe to omit from the useEffect or useCallback dependency list.
That’s strange, setIsSessionMode(!isSessionMode) seems to work but setState with callback syntax does not. Don’t understand why.
In fact I also have same app built in codepen [here] which I built earlier (https://codepen.io/abhi747/pen/eYZNbpb), where the setState with callback syntax is working perfectly fine.
I am just incorporating the app in codesandbox, to segregate different components in different files as it is not possible to create files in codepen.
I need to have state flag (isSessionMode) to conditionally render session mode title in the UI i.e, ‘Session’ or ‘Break’ .