keepcalculator

06 Numbers and Powers

React Re-renders: Component Calls and DOM Updates

Card No. 06·10012 · Updated · Standard formula, shown below

Average pace 5.00 min/km
Average speed
12.00 km/h
Result
Finish time
50 min
You entered
Distance
10 km
You entered
You enter
Finish time, Distance
You get
Average pace, Average speed
Rounding
2 dp

React re-renders are the process by which React updates the user interface when state or props change, but the component function itself is called again while the actual DOM is only changed where needed. This article explains exactly what triggers a re-render, what happens during a component call, and how React decides which parts of the real DOM to update.

Formula

The calculator above is a simple pace calculator, not related to React, but it demonstrates the kind of pure function that React components resemble. The formula for pace is:

pace = finish time (min) ÷ distance (km)

And speed = distance (km) ÷ (finish time (min) ÷ 60)

Where finish time is in minutes, distance in kilometers, pace in minutes per kilometer, and speed in kilometers per hour. This pure relationship—same inputs always give the same outputs—mirrors how React expects components to behave.

Worked Example

Using the default values: finish time = 50 minutes, distance = 10 km.

Step 1: pace = 50 ÷ 10 = 5.00 min/km

Step 2: speed = 10 ÷ (50 ÷ 60) = 10 ÷ 0.8333 = 12.00 km/h

The calculator block gives the same results: 5.00 min/km and 12.00 km/h.

What Actually Happens During a Re-render

When a component re-renders, React calls the component function again. That function returns a new description of what the UI should look like—a React element tree. React then compares this new tree with the previous one (a process called reconciliation) to figure out what changed. Only the differences are applied to the real DOM.

This means the component function is called, but the browser’s DOM is not rebuilt from scratch. For example, if a counter component re-renders because its state changed from 1 to 2, React updates the text node containing “2” and leaves the rest of the page untouched.

What Triggers a Re-render

Three main things cause a component to re-render:

  • State changes: Calling the setter from useState or dispatching an action from useReducer schedules a re-render of that component.
  • Props changes: When a parent component re-renders, it passes new props to its children. Unless a child is memoized, it re-renders even if the props are identical by value.
  • Context changes: If a component consumes a context whose value changes, it re-renders, regardless of props.

A common misconception is that a component re-renders when its parent re-renders. That is true by default, but it is not because the child’s props changed—it is because React re-renders all children of a re-rendering parent unless explicitly prevented.

Component Calls vs. DOM Updates

The key distinction is that a component call is cheap; a DOM update is expensive. React calls every component function in a tree that is not memoized, but it only touches the DOM for nodes that actually changed. This is why you can have a large app with thousands of components and still get smooth updates—React’s diffing algorithm minimizes DOM operations.

However, component calls are not free. If a component has expensive computations inside its body (like filtering a large array), those computations run on every re-render, even if the result is the same. This is where useMemo and React.memo come in.

How to Prevent Unnecessary Re-renders

You can control re-renders with a few tools:

  • React.memo: Wraps a component so it only re-renders when its props change (by shallow comparison).
  • useMemo: Caches the result of a computation until its dependencies change.
  • useCallback: Returns a stable function reference so child components don’t re-render because the function identity changed.
  • State colocation: Keep state as close as possible to where it is used, so fewer components re-render.

But be careful: overusing these can make your code harder to read and can even hurt performance if the comparison itself is costly. React’s default behavior is fine for most apps.

Common Problems and Misconceptions

One frequent issue is that developers put a new array or object inline in JSX, like <Child items={[1,2,3]} />. This creates a new array every render, so React.memo sees a different prop and re-renders anyway. The fix is to define the array outside the component or use useMemo.

Another misconception is that key props affect re-renders. Keys are used for reconciliation, not for preventing re-renders. Changing a key will cause React to unmount and remount a component, which resets its local state.

Also, state updates are batched in React 18 and later. If you call setState twice in the same event handler, React only re-renders once. This is a performance optimization, not a bug.

How to Debug Re-renders

To see which components re-render, you can use the React DevTools Profiler. It records every render and shows you the duration and the reason. You can also temporarily add a console.log inside a component body to see when it is called.

Another technique is to use the why-did-you-render library, which logs unnecessary re-renders. But a simpler approach is to ask: “Is this component’s output actually changing?” If not, it should probably be memoized.

Performance Costs and When to Care

Re-renders are not inherently bad. React is designed to handle them efficiently. The cost comes from:

  • Large component trees (thousands of components).
  • Expensive render logic (complex calculations, large data transformations).
  • Frequent updates (like typing in an input field).

If your app feels slow, profile it first. Premature optimization can waste time. In practice, most apps do not need aggressive memoization until they have a measurable problem.

Frequently Asked Questions

Does a re-render mean the DOM is updated? No. A re-render means the component function is called and a new element tree is produced. React then diffs that tree with the previous one and only updates the DOM where the output actually changed. If the output is identical, the DOM is untouched.

Why does my child component re-render when its props haven’t changed? Because by default, when a parent re-renders, React re-renders all children. The child’s props might be the same, but the parent’s new element tree creates new element objects, so React doesn’t know the child can be skipped. Use React.memo to tell React to skip a child if its props are shallowly equal.

What is the difference between useMemo and React.memo? React.memo is a higher-order component that prevents a component from re-rendering if its props don’t change. useMemo is a hook that caches the result of a calculation inside a component. They solve different problems: one avoids re-rendering the component, the other avoids redoing expensive work during a render.

Does useState always trigger a re-render? No. If you set the state to the same value as the current state (using Object.is comparison), React will bail out and not re-render the component. This is an optimization to avoid unnecessary work.

How can I force a re-render? You generally shouldn’t. If you need to re-render, it usually means your state is not structured correctly. However, you can use a state updater function that returns a new object each time, or use the useReducer hook with a dispatch that always returns a new state. A common hack is const [, forceUpdate] = useReducer(x => x + 1, 0), but it’s a last resort.

Related

Formula used
in t | Finish time | min | 50 | 0
in d | Distance | km | 10 | 0 | 100000
out pace | Average pace | min/km | t / d | 2
out speed | Average speed | km/h | d / (t / 60) | 2

Each line is one input (in, sel, list) or one result (out: label, unit, formula, decimals). How the calculators work

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.

More cards in this drawer

The whole Numbers and Powers drawer →