{"record":{"id":"80892f8c5e844a3e","repo":"facebook/react","slug":"too-many-re-renders-react-limits-the-number-of-re","errorCode":null,"errorMessage":"Too many re-renders. React limits the number of renders to prevent an infinite loop.","messagePattern":"Too many re-renders\\. React limits the number of renders to prevent an infinite loop\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react-server/src/ReactFizzHooks.js","lineNumber":565,"sourceCode":"    const ref = {current: initialValue};\n    if (__DEV__) {\n      Object.seal(ref);\n    }\n    // $FlowFixMe[incompatible-use] found when upgrading Flow\n    workInProgressHook.memoizedState = ref;\n    return ref;\n  } else {\n    return previousRef;\n  }\n}\n\nfunction dispatchAction<A>(\n  componentIdentity: Object,\n  queue: UpdateQueue<A>,\n  action: A,\n): void {\n  if (numberOfReRenders >= RE_RENDER_LIMIT) {\n    throw new Error(\n      'Too many re-renders. React limits the number of renders to prevent ' +\n        'an infinite loop.',\n    );\n  }\n\n  if (componentIdentity === currentlyRenderingComponent) {\n    // This is a render phase update. Stash it in a lazily-created map of\n    // queue -> linked list of updates. After this render pass, we'll restart\n    // and apply the stashed updates on top of the work-in-progress hook.\n    didScheduleRenderPhaseUpdate = true;\n    const update: Update<A> = {\n      action,\n      next: null,\n    };\n    if (renderPhaseUpdates === null) {\n      renderPhaseUpdates = new Map();\n    }\n    const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);","sourceCodeStart":547,"sourceCodeEnd":583,"githubUrl":"https://github.com/facebook/react/blob/eafeac097ba51e1eab809c07102126bd5f8e5425/packages/react-server/src/ReactFizzHooks.js#L547-L583","documentation":"dispatchAction in Fizz throws when a state setter is called during render more than RE_RENDER_LIMIT (25) times. Each render-phase update makes React re-run the component immediately; an unconditional or insufficiently guarded setter call loops forever, and the limit stops the infinite loop.","triggerScenarios":"const [n, setN] = useState(0); setN(n + 1) in the body of a server-rendered component; setters invoked in render helpers without the change-guard the render-phase-update pattern requires; the same setter firing on every render pass so the count climbs to 25.","commonSituations":"Derived-state patterns ('sync state to props') written as an immediate setState during render; one-time initialization implemented as setState at render; client code with effect-based updates migrated into SSR'd components.","solutions":["Guard render-phase updates: only call the setter when the value actually changed (if (state.source !== prevProp) setState(...)) so React settles after one re-render","Derive the value during render instead of storing it — remove the state entirely","If the update must happen later, move it to a client component event handler or effect"],"exampleFix":"// before\nfunction Counter() {\n  const [n, setN] = useState(0);\n  setN(n + 1); // setter every render -> 25 re-renders -> throws\n  return <p>{n}</p>;\n}\n\n// after\nfunction Counter() {\n  const [n, setN] = useState(0);\n  return <button onClick={() => setN(n + 1)}>{n}</button>;\n}","handlingStrategy":"try-catch","validationCode":"// The supported render-phase update pattern: only setState when the value changed.\nconst [state, setState] = useState({source: props.value, data: null});\nif (state.source !== props.value) {\n  setState(s => ({...s, source: props.value})); // settles after one re-render\n}","typeGuard":null,"tryCatchPattern":"const {pipe} = renderToPipeableStream(<App/>, {\n  onError(err) {\n    if (String(err.message).includes('Too many re-renders')) {\n      // An unguarded setter runs during render — log the component stack and fail the render.\n      logError(err);\n    }\n  },\n});","preventionTips":["Never call a setter unconditionally during render — guard it with a changed-value check","Prefer deriving values during render over storing and syncing them in state","Reserve updates for event handlers and effects; SSR should be a pure single pass"],"tags":["hooks","setstate","infinite-loop","render-phase-update","ssr"],"backgroundTag":"infinite-render-loop","analyzedSha":"eafeac097ba51e1eab809c07102126bd5f8e5425","analyzedAt":"2026-08-21T22:01:08.818Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}