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: state update from a rAF in useLayoutEffect not batched when using createRoot #32021

Open
mxmul opened this issue Jan 8, 2025 · 1 comment
Labels
Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug

Comments

@mxmul
Copy link

mxmul commented Jan 8, 2025

Recreating #28457, which was closed due to staleness.

Maybe a weird edge case, but this caused an unexpected visual change in our app when migrating a root from ReactDOM.render.

React version: 18.2.0

Steps To Reproduce

  1. Define a component that has some state, and a useLayoutEffect that modifies the state in a requestAnimationFrame callback. like:
function App() {
  const [message, setMessage] = React.useState("Loading...");

  React.useLayoutEffect(() => {
    requestAnimationFrame(() => {
      setMessage("Ready");
    });
  });
  return <p>{message}</p>;
}
  1. Mount the component using ReactDOM.render, and you will never observe the component with its initial state ("Loading..."). Only the updated state ("Ready").
  2. Mount the component with createRoot and root.render, and you will observe the component render twice. Once with the initial state ("Loading..."), then with the updated state ("Ready").

Link to code example: https://codepen.io/mxmul/pen/abMexLe

react-batching.webm

The current behavior

Two renders - once with the initial state, and a second with the updated state.

The expected behavior

A single render with the updated state. This seems to be the behavior before React 18.

@mxmul mxmul added the Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug label Jan 8, 2025
@chiragjha1
Copy link

This behavior is expected in concurrent rendering and StrictMode in React 18.

To solve this issue,

  • Move state updates from useLayoutEffect to useEffect
  • Use React.startTransition for non-urgent updates
  • Opt out of StrictMode during development if necessary

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

2 participants