Build a 25 + 5 Clock useState setTimer lag

I know a lot of people call it asynchronous and it might be a useful mental model but it does obscure the truth. The state setter function is not asynchronous, it’s not like it returns a promise.

Your example is in fact a “render issue” and not because the state setter function is asynchronous. You do not see the new value logged because React hasn’t re-rendered yet, not because the state setter is asynchronous. On the next render, the state is the new value, not on the current render.

If you want to log the state as it changes useEffect can be handy but you can often also just log the value you are setting (not the state, but the actual value you are setting).

const nextCount = count + 1;
setCount(nextCount);

console.log(count);     // 0
console.log(nextCount); // 1
useEffect(() => {
  console.log(count);
}, [count])

React docs: I’ve updated the state, but logging gives me the old value


I would caution against comparing useEffect to the old lifecycle methods. That usually gets people into trouble.

Just because you can do something with useEffect doesn’t mean you should. It is (rightly so I’d say) one of the more criticized React hooks and its API is dangerously close to being a footgun.

I’m not saying it doesn’t have its uses but its main purpose is synchronization with external systems. The new React docs are a lot clearer about its use and pitfalls. I don’t think they did a very good job of teaching the hook initially which is one of the reasons why it is often “misused”.

To quote the docs I linked to directly.

Effects are an escape hatch from the React paradigm. They let you “step outside” of React and synchronize your components with some external system like a non-React widget, network, or the browser DOM. If there is no external system involved (for example, if you want to update a component’s state when some props or state change), you shouldn’t need an Effect. Removing unnecessary Effects will make your code easier to follow, faster to run, and less error-prone.


So, when we say “render” we mean the redrawing of the webpage?

And setting the state is linked to the re-render, which does not necessarily occur after each setState?

Maybe async isn’t the correct term, but setting state is not immediate, let’s say. That’s why this does not work:

console.log(timer) //2
setTimer(timer += 1)
console.log(timer) //2

And it’s designed this way to avoid updating too often? It’s just hard for me to understand how this design is useful, to update a state but it doesn’t happen immediately.

So, I should avoid useEffect if I’m not really interacting with something outside of React. Was this approach correct then? (to update the Timer value when clicking the “Session Length” button to update both values. I thought this was a requirement but now I can’t find that, I think I was just copying what the example clock does https://clock.freecodecamp.rocks/)

setSession(parseInt(session)+1);
setTimer(parseInt(session) + 1 + ":00")

I’ll check out these videos and links, thank you!

Ok, in this first video he has a solution basically like mine, he adds a variable to avoid the same operation twice:

const newValue = parseInt(session) + 1;
setSession(newValue);
setTimer(newValue + ":00")

But then he goes on to solve the problem with useEffect, even though:

If there is no external system involved (for example, if you want to update a component’s state when some props or state change), you shouldn’t need an Effect.

Insightful point though about the setSearch() function setting the variable in memory but the search variable returning a copy of that string and how this causes the lag in update.

Re-rendering means re-running the components with the newly updated state that caused the components to re-render in the first place.

You can’t separate the re-rendering from the component re-running they are part of the same process. The VDOM is used (diffing) to make sure the actual DOM updates ("redrawing ") are targeted to the specific nodes/node content that changed.

There is a comment on the video about that and he does say you do not need to use it.

I think he is just showing how it might work. He gives a hypothetical where you have other elements that also can set the search but he doesn’t actually show it. He just shows how to tie the fetch to a single changing state value so no matter what changes the value the fetch is called. The example isn’t really fleshed out enough to say what other options might be better. I would suggest having a select/option element for the predefined values and using the same handler for both inputs might be a better solution.

Setting state inside a useEffect is often a code smell and usually isn’t necessary but I wouldn’t get overly dogmatic about it. The point is to avoid having effects when they are not needed and to consider the options before blindly using them.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.