跪拜 Guibai
← All articles
React.js · Frontend · Interview

What Actually Runs When a React Component Re-renders

By Revolution61 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Misreading console logs as evidence of wasteful DOM updates leads developers to prematurely add memoization or restructure state, making code harder to maintain without fixing a real bottleneck. Understanding the render-versus-commit split and Effect dependency rules prevents the most common React performance dead ends.

Summary

When a React component re-renders, the entire function body executes again: local variables, derived calculations like total price, event handlers, and the returned JSX all get new values based on the latest props and state. State itself, however, is preserved by React across renders—the initial value passed to useState is ignored after the first mount.

React then diffs the new JSX against the previous output and commits only the necessary DOM changes. A component function logging twice does not mean the DOM was rebuilt twice. Effects follow their own dependency rules; a component re-executing does not force every Effect to re-synchronize.

Side effects like network requests or DOM mutations belong in event handlers or Effects, not directly in the render body. Before reaching for useMemo or useCallback, developers should first confirm that a re-render is actually causing a measurable performance problem, not just extra log lines.

Takeaways
Calling a state setter schedules a re-render, which re-executes the entire component function body with the new state value.
useState(initialValue) uses initialValue only on the first render; subsequent renders return the current state, ignoring the initial argument.
Local variables declared in the component body are recreated on every render and do not persist across renders.
Derived values like totalPrice should be computed directly during rendering rather than stored in state and synchronized via an Effect.
React diffs the new JSX against the previous output and commits only the changed DOM nodes, not the entire tree.
A component function re-executing does not mean every useEffect inside it re-runs; Effects re-synchronize only when their dependency array values change.
Strict Mode in development can double-invoke component functions and Effects, so log counts in dev do not reflect production behavior.
Modifying external data (module-level arrays, DOM, storage) directly inside the render body produces unpredictable results because renders can happen multiple times.
Premature useMemo, useCallback, or React.memo adds complexity without benefit unless a profiler confirms an expensive calculation or unwanted child re-render.
Investigating a re-render starts with finding the state update source, then checking the render body, Effect dependencies, and final DOM changes before considering optimization.
Conclusions

Many React developers conflate "the component function ran" with "the DOM updated," which leads to unnecessary optimization work. The render phase is pure computation; only the commit phase touches the DOM.

The article's distinction between state, local variables, and derived data is a mental model that, once internalized, eliminates an entire category of useEffect overuse and stale-closure bugs.

Strict Mode's double-invocation is still widely misunderstood as a bug rather than a development-only purity check, causing developers to mistrust their own logging.

The advice to defer useMemo and useCallback until a profiler shows a problem runs counter to much online React content that treats them as default safeguards, but it aligns with the React team's own recommendations.

Concepts & terms
Render phase
React calls component functions to calculate the next JSX output. This phase is pure computation and does not modify the DOM.
Commit phase
React applies the calculated changes to the DOM, runs ref callbacks, and synchronizes Effects. Only nodes that differ from the previous output are updated.
Derived state
Values computed directly from existing props or state during rendering, such as totalPrice = unitPrice * quantity. Storing them separately in state risks synchronization bugs.
Strict Mode double-invocation
In development, React intentionally calls component functions and Effect setup/cleanup twice to surface impure logic. This does not happen in production.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗