Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: setState inside setInterval runs async first and then sync #32265

Open
TusharShahi opened this issue Jan 29, 2025 · 6 comments
Open

Bug: setState inside setInterval runs async first and then sync #32265

TusharShahi opened this issue Jan 29, 2025 · 6 comments
Labels
Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug

Comments

@TusharShahi
Copy link

React version: 19

Steps To Reproduce

  1. Schedule an interval which runs a certain number of times (inside an effect).
  2. Update a state value inside that interval.
  3. Ensure that you are using setState update function pattern. Although the other pattern also works, this one is easy for logs.
const useTypewriter = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    let i = 0;
    // console.log("called");
    const interval = setInterval(() => {
      console.log({ i });
      if (i < 5) {
        setCount((count) => {
          console.log("inside callback");
          return 0 + i;
        });

        console.log("now"); //Initially this logs after "inside callback", but after two iterations it logs before "inside callback"
        i++;
      } else {
        clearInterval(interval);
      }
    }, 200);

    return () => {
      clearInterval(interval);
    };
  }, []);

  console.log({ count });
};

Link to code example: https://codesandbox.io/p/sandbox/amazing-rain-forked-5knv6z?workspaceId=ws_XcXHczGEnBvM34o6MyJMXt

The current behavior

In the initial iteration the setState callback is called synchronously but later it is called asynchronously.

The expected behavior

setState to behave same in all iterations.

@TusharShahi TusharShahi added the Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug label Jan 29, 2025
@V3RON
Copy link
Contributor

V3RON commented Jan 30, 2025

Could you please double-check whether the sandbox is marked as public?

It's likely that the Sandbox you're trying to access doesn't exist or you don't have the required permissions to access it.

@TusharShahi
Copy link
Author

Could you please double-check whether the sandbox is marked as public?

It's likely that the Sandbox you're trying to access doesn't exist or you don't have the required permissions to access it.

Dumb move. Made the change.

@Mankumanki
Copy link

I checked and what I found is on first rendering or on Mounting of react component the log inside setState() always gets executed first and then for next renders the behavior is again normal . In your case for first two times it is behaving synchronously because for first time your count value is not changing it is still zero so there is no re-render and it prints synchronously, for second time the count value changes first time but since it is re-rendering for first time it is still behaving synchronously, after that when count is updated the behavior is normal again. Try changing your initial value of i=1 it will behave like that only for first iteration or first re-render that I was saying above.

What I am not able to understand is why for every first render it is behaving synchronously and then async. It is for first time only not sure why?

@TusharShahi
Copy link
Author

Yes, I am aware of the behaviour. Only the first render is behaving differently. Still do not understand why and could not find any relevant docs pointing towards this.

@Shiva-017
Copy link

I tested it, I believe it's due to the batching of state changes in react, when I force the synchronous state changes using flushSync, this won't happen.

@TusharShahi
Copy link
Author

TusharShahi commented Jan 31, 2025

Yes, React 16 behaves consistently. So it has to do with the batching React 18 introduced i assume

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug
Projects
None yet
Development

No branches or pull requests

4 participants