Skip to content

Conversation

@rickhanlonii
Copy link
Member

@rickhanlonii rickhanlonii commented Nov 8, 2025

Overview

Add a feature flag disableSetStateInRenderOnMount to start experimenting with warning for setState in initial render.

Motivation

The main reason to start warning about this now is that supporting this prevents us from landing SSR optimizations such as inlining hooks and removing code to support updates during SSR. But this also indicates a performance issue in the app that can usually be easily fixed.

Pattern isn't useful

Usually, calling setState in initial render of a component is an accident, by forgetting to pass the initial value into useState():

function Component({value}) {
  const [prev, setPrev] = useState();   // 🚩 oops!
  if (prev !== value) {
    setPrev(value);
  }
}

For those use cases, the warning will fire and applying an easy fix to pass the inital state will give performance benefits since we won't need to immediately re-render a component on mount.

function Component({value}) {
  const [prev, setPrev] = useState(value);   // 😎
  if (prev !== value) {
    setPrev(value);
  }
}

Now this will setState in render on updates.

Future SSR improvements

If this pattern is fixed, we could compile the SSR bundle code from:

function Component({value}) {
  const [prev, setPrev] = useState(value);
  if (prev !== value) {
    setPrev(value);
  }
  const derivedValue = useMemo(() => {
    return value.filter(Boolean);
  }, value);
  
  //...
}

To:

function Component({value}) {
  const [prev, setPrev] = [value, () => {}];
  const derivedValue = value.filter(Boolean);
    
  //...
}

This could be a huge speedup in SSR performance.

Experiment

To confirm how many cases fall into the easy fix, I'm rolling out a feature flag to test it in a large app to see what use cases are depending on this, and how difficult the fixes are.

Review

It's a pain to update the tests for Fiber and Fizz in different PRs because of the server integration tests.

Here's how the different warnings are implemented in separate commits:

@meta-cla meta-cla bot added the CLA Signed label Nov 8, 2025
@github-actions github-actions bot added the React Core Team Opened by a member of the React Core Team label Nov 8, 2025
@react-sizebot
Copy link

react-sizebot commented Nov 8, 2025

Comparing: 5e94655...dca4fcc

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.js = 6.68 kB 6.68 kB = 1.83 kB 1.83 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 608.16 kB 608.07 kB +0.04% 107.65 kB 107.69 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.69 kB 6.69 kB = 1.83 kB 1.83 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 666.18 kB 665.99 kB +0.03% 117.35 kB 117.39 kB
facebook-www/ReactDOM-prod.classic.js = 693.31 kB 693.36 kB +0.03% 121.97 kB 122.02 kB
facebook-www/ReactDOM-prod.modern.js = 683.73 kB 683.78 kB +0.03% 120.36 kB 120.40 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
oss-experimental/react-server/cjs/react-server.production.js +0.49% 148.59 kB 149.32 kB +0.14% 26.22 kB 26.25 kB
test_utils/ReactAllWarnings.js +0.36% 66.51 kB 66.75 kB +0.23% 16.74 kB 16.78 kB
oss-experimental/react-markup/cjs/react-markup.production.js +0.32% 246.71 kB 247.51 kB +0.11% 45.74 kB 45.79 kB
facebook-www/ReactDOMServerStreaming-prod.modern.js +0.30% 266.45 kB 267.25 kB +0.10% 48.71 kB 48.76 kB
oss-experimental/react-server/cjs/react-server.development.js +0.28% 209.81 kB 210.39 kB +0.04% 37.04 kB 37.05 kB
facebook-www/ReactDOMServerStreaming-dev.modern.js +0.28% 413.37 kB 414.52 kB +0.21% 74.03 kB 74.19 kB
oss-experimental/react-dom/cjs/react-dom-server.browser.production.js +0.28% 288.60 kB 289.40 kB +0.12% 51.00 kB 51.06 kB
oss-experimental/react-dom/cjs/react-dom-server.bun.production.js +0.28% 289.35 kB 290.15 kB +0.10% 50.80 kB 50.85 kB
oss-experimental/react-dom/cjs/react-dom-server.edge.production.js +0.27% 294.90 kB 295.70 kB +0.11% 53.34 kB 53.40 kB
oss-experimental/react-dom/cjs/react-dom-server.node.production.js +0.26% 302.62 kB 303.42 kB +0.11% 53.19 kB 53.25 kB
oss-experimental/react-markup/cjs/react-markup.react-server.production.js +0.22% 355.69 kB 356.49 kB +0.08% 66.15 kB 66.20 kB
oss-experimental/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js = 2,149.34 kB 2,143.41 kB = 308.97 kB 307.78 kB
oss-stable-semver/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js = 2,149.34 kB 2,143.41 kB = 308.97 kB 307.78 kB
oss-stable/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js = 2,149.34 kB 2,143.41 kB = 308.97 kB 307.78 kB
oss-experimental/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.production.js = 2,144.87 kB 2,138.94 kB = 307.97 kB 306.77 kB
oss-stable-semver/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.production.js = 2,144.87 kB 2,138.94 kB = 307.97 kB 306.77 kB
oss-stable/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.production.js = 2,144.87 kB 2,138.94 kB = 307.97 kB 306.77 kB

Generated by 🚫 dangerJS against dca4fcc

@gaearon
Copy link
Collaborator

gaearon commented Nov 9, 2025

Maybe “during the initial render”? Set state “on mount” usually refers to doing it in an effect which isn’t what this seems to be about.

Also, “this behavior is deprecated” maybe could be “this is deprecated, pass the initial value to useState instead” or something like that so it’s clear how to fix it.

@rickhanlonii rickhanlonii force-pushed the rh/set-state-mount-error branch 2 times, most recently from 11f09d6 to 96509c5 Compare November 11, 2025 20:56
@rickhanlonii rickhanlonii changed the title [wip] warn for setState in render on initial mount [flag] warn for setState in render on initial mount Nov 11, 2025
@rickhanlonii rickhanlonii requested review from acdlite and sebmarkbage and removed request for sebmarkbage November 11, 2025 21:29
@rickhanlonii
Copy link
Member Author

Thanks @gaearon, message updated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed React Core Team Opened by a member of the React Core Team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants