Skip to content

Bug: useEffect fails to fire for every render under extreme conditions #34730

@mnbroatch

Description

@mnbroatch

React version: 19.1.0

Steps To Reproduce

mount this component, look at console. Refresh a few times.

Refreshing produces different output every time. it's fine that different numbers of renders happen due to behind-the-scenes batching, but my understanding is that renders and effects should be 1-to-1 with no dependency array.

I also have no idea why different values of timeout seem to be relevant.

Caused a real-world bug recently where I had a forceUpdate() in an event subscriber that was busy on init in a custom hook, with queries firing simultaneously to rerender the consumer of that hook.


import { useEffect, useReducer } from "react";

export default function App() {
  const [_, forceUpdate] = useReducer((x) => !x, false);

  useThrash();

  console.log("RENDER");
  useEffect(() => {
    console.log("EFFECT");
  });

  useEffect(() => {
    setTimeout(() => {
      forceUpdate();
    }, 10);
  }, []);
}

const useThrash = () => {
  const [_, forceUpdate] = useReducer((x) => !x, false);
  useEffect(() => {
    setTimeout(() => {
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
      forceUpdate();
    }, 1);
  }, []);
};

https://codesandbox.io/p/sandbox/vyn5zj

expected: same number of renders and effect runs
actual: more renders than effect runs

example output:

RENDER
02:21:02.077 RENDER
02:21:02.081 EFFECT
02:21:02.085 RENDER
02:21:02.095 RENDER

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions