React re-renders guide: preventing unnecessary re-renders
Tags: javascript, webdev, react, performance
Published: 2022-08-17 10:47:30


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/anmew3h3rub30i36lg6q.png)


Originally published at [https://www.developerway.com](https://www.developerway.com). The website has more articles like this 😉

---

This is the second part of [React re-renders guide: everything, all at once]
(https://www.developerway.com/posts/react-re-renders-guide). There are no investigations, no explorations in this guide, just raw facts and LOTs of patterns. Each pattern is linkable independently and has:

​- a short description
- visual aid that demonstrates the pattern
- working code example in codesandbox
- links to deep dives where necessary

The intention here was to create something that can be referenced on a regular basis when writing components or fixing performance problems. Or shared with a struggling teammate as a link to an exact pattern. Or maybe even printed and hang on walls so it’s always in front of the eyes 😄

The full guide table of content: 

<ul>
        <li>
          <a href="https://www.developerway.com/posts/react-re-renders-guide#part1">Part 1: what is re-render in React?</a>
        </li>
        <li>
          <a href="https://www.developerway.com/posts/react-re-renders-guide#part2">Part 2: when React component re-renders itself?</a>
        </li>
        <li>
          <a href="https://www.developerway.com/posts/react-re-renders-guide#part3">Part 3: preventing re-renders with composition</a>
        </li>
        <li>
          <a href="https://www.developerway.com/posts/react-re-renders-guide#part4">Part 4: preventing re-renders with React.memo</a>
        </li>
        <li>
          <a href="https://www.developerway.com/posts/react-re-renders-guide#part5">Part 5: improving re-renders performance with useMemo/useCallback</a>
        </li>
        <li>
          <a href="https://www.developerway.com/posts/react-re-renders-guide#part6">Part 6: improving re-renders performance of lists</a>
        </li>
        <li>
          <a href="https://www.developerway.com/posts/react-re-renders-guide#part7">Part 7: preventing re-renders caused by Context</a>
        </li>
      </ul>

---


<h2>Preventing re-renders with composition</h2>

<h3>⛔️ Antipattern: Creating components in render function</h3>

Creating components inside render function of another component is an anti-pattern that can be the biggest performance killer. On every re-render React will re-mount this component (i.e. destroy it and re-create it from scratch), which is going to be much slower than a normal re-render. On top of that, this will lead to such bugs as:

* possible “flashes” of content during re-renders
* state being reset in the component with every re-render
* useEffect with no dependencies triggered on every re-render
* if a component was focused, focus will be lost

[See example in codesandbox](https://codesandbox.io/s/part-3-1-creating-components-inline-t2vmkj?file=/src/App.tsx)

Additional resources to read: [How to write performant React code: rules, patterns, do's and don'ts](https://www.developerway.com/posts/how-to-write-performant-react-code)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d1r387bxf1tkdaqr8i0f.png)

<h3>✅ Preventing re-renders with composition: moving state down</h3>

This pattern can be beneficial when a heavy component manages state, and this state is only used on a small isolated portion of the render tree. A typical example would be opening/closing a dialog with a button click in a complicated component that renders a significant portion of a page.

In this case, the state that controls modal dialog appearance, dialog itself, and the button that triggers the update can be encapsulated in a smaller component. As a result, the bigger component won’t re-render on those state changes.

[See example in codesandbox](https://codesandbox.io/s/part-3-2-moving-state-down-vlh4gf?file=/src/App.tsx)

Additional resources to read: [The mystery of React Element, children, parents and re-renders](https://www.developerway.com/posts/react-elements-children-parents), [How to write performant React code: rules, patterns, do's and don'ts](https://www.developerway.com/posts/how-to-write-performant-react-code)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8xv2zmsbb8tmfn60h4sd.png)

<h3>✅ Preventing re-renders with composition: children as props</h3>

This can also be called “wrap state around children”. This pattern is similar to “moving state down”: it encapsulates state changes in a smaller component. The difference here is that state is used on an element that wraps a slow portion of the render tree, so it can’t be extracted that easily. A typical example would be `onScroll` or `onMouseMove` callbacks attached to the root element of a component.

In this situation, state management and components that use that state can be extracted into a smaller component, and the slow component can be passed to it as `children`. From the smaller component perspective `children` are just prop, so they will not be affected by the state change and therefore won’t re-render.

[See example in codesandbox](https://codesandbox.io/s/part-3-3-children-as-props-59icyq?file=/src/App.tsx)

Additional resources to read: [The mystery of React Element, children, parents and re-renders](https://www.developerway.com/posts/react-elements-children-parents)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mn3iau6dx398m080klhy.png)

<h3>✅ Preventing re-renders with composition: components as props</h3>

Pretty much the same as the previous pattern, with the same behavior: it encapsulates the state inside a smaller component, and heavy components are passed to it as props. Props are not affected by the state change, so heavy components won’t re-render.

Can be useful when a few heavy components are independent from the state, but can’t be extracted as children as a group.

[See example in codesandbox](https://codesandbox.io/s/part-3-4-passing-components-as-props-9h3o5u?file=/src/App.tsx)

Read more about passing components as props here: [React component as prop: the right way™️](https://www.developerway.com/posts/react-component-as-prop-the-right-way), [The mystery of React Element, children, parents and re-renders](https://www.developerway.com/posts/react-elements-children-parents)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9rgyre9wrx5xckrh3u0y.png)

---

<h2>Preventing re-renders with React.memo</h2>

Wrapping a component in `React.memo` will stop the downstream chain of re-renders that is triggered somewhere up the render tree, unless this component’s props have changed.

This can be useful when rendering a heavy component that is not dependent on the source of re-renders (i.e. state, changed data).

[See example in codesandbox](https://codesandbox.io/s/part-4-simple-memo-fz4xhw?file=/src/App.tsx)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xxgnolm16hjq5sim090e.png)

<h3>✅ React.memo: component with props</h3>

**All props** that are not primitive values have to be memoized for React.memo to work

[See example in codesandbox](https://codesandbox.io/s/part-4-1-memo-on-component-with-props-fq55hm?file=/src/App.tsx)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2r6sgz1ld2a5tmiixyzn.png)

<h3>✅ React.memo: components as props or children</h3>

`React.memo` has to be applied to the elements passed as children/props. Memoizing the parent component will not work: children and props will be objects, so they will change with every re-render.

See here for more details on how memoization works for children/parent relationships:  [The mystery of React Element, children, parents and re-renders](https://www.developerway.com/posts/react-elements-children-parents)

[See example in codesandbox](https://codesandbox.io/s/part-4-2-memo-on-components-in-props-55tebl?file=/src/App.tsx)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ei1pl3x0pir8vf9eh4l5.png)

---

<h2>Improving re-renders performance with useMemo/useCallback</h2>

<h3>⛔️ Antipattern: unnecessary useMemo/useCallback on props</h3>

Memoizing props by themselves will not prevent re-renders of a child component. If a parent component re-renders, it will trigger re-render of a child component regardless of its props.

[See  example in codesandbox](https://codesandbox.io/s/part-5-1-unnecessary-usememo-lmk8fq?file=/src/App.tsx)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d1qvpkuo131e21d37cxb.png)

<h3>✅ Necessary useMemo/useCallback</h3>

If a child component is wrapped in `React.memo`, all props that are not primitive values have to be memoized

[See  example in codesandbox](https://codesandbox.io/s/part-5-2-usememo-in-props-trx97x?file=/src/App.tsx)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zipo6goels6ux3c5jn0v.png)

If a component uses non-primitive value as a dependency in hooks like `useEffect`, `useMemo`, `useCallback`, it should be memoized.

[See  example in codesandbox](https://codesandbox.io/s/part-5-2-usememo-in-effect-88tbov)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cewj2gmz4n1pc7lrwmqo.png)

<h3>✅ useMemo for expensive calculations</h3>

One of the use cases for `useMemo` is to avoid expensive calculations on every re-render.

`useMemo` has its cost (consumes a bit of memory and makes initial render slightly slower), so it should not be used for every calculation. In React, mounting and updating components will be the most expensive calculation in most cases (unless you’re actually calculating prime numbers, which you shouldn’t do on the frontend anyway).

As a result, the typical use case for `useMemo` would be to memoize React elements. Usually parts of an existing render tree or results of generated render tree, like a map function that returns new elements.

The cost of “pure” javascript operations like sorting or filtering an array is usually negligible, compare to components updates.

[See  example in codesandbox](https://codesandbox.io/s/part-5-3-usememo-for-expensive-calculations-trx97x?file=/src/App.tsx)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vynhpiumh8zcvqqrex6c.png)

---

<h2>Improving re-render performance of lists</h2>

In addition to the regular re-renders rules and patterns, the `key` attribute can affect the performance of lists in React.

**Important**: just providing `key` attribute will not improve lists' performance. To prevent re-renders of list elements you need to wrap them in `React.memo` and follow all of its best practices.

Value in `key` should be a string, that is consistent between re-renders for every element in the list. Typically, item’s `id`  or array’s `index` is used for that.

It is okay to use array’s `index` as key, if the list is **static**, i.e. elements are not added/removed/inserted/re-ordered.

Using array’s index on dynamic lists can lead to:

* bugs if items have state or any uncontrolled elements (like form inputs)
* degraded performance if items are wrapped in React.memo

Read about this in more details here: [React key attribute: best practices for performant lists](https://www.developerway.com/posts/react-key-attribute).

[See  example in codesandbox - static list](https://codesandbox.io/s/part-6-static-list-with-index-and-id-as-key-7i0ebi?file=/src/App.tsx)

[See  example in codesandbox - dynaminc list](https://codesandbox.io/s/part-6-dynamic-list-with-index-and-id-as-key-s50knr?file=/src/App.tsx)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fibklic75qdc4kpw0rx3.png)

<h3>⛔️ Antipattern: random value as key in lists</h3>

Randomly generated values should never be used as values in `key` attribute in lists. They will lead to React re-mounting items on every re-render, which will lead to:

* very poor performance of the list
* bugs if items have state or any uncontrolled elements (like form inputs)

[See example in codesandbox](https://codesandbox.io/s/part-6-1-random-values-in-keys-z1zhy6?file=/src/App.tsx)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2ynvera26pzvq9nonma4.png)

---

<h2>Preventing re-renders caused by Context</h2>

<h3>✅ Preventing Context re-renders: memoizing Provider value</h3>

If Context Provider is placed not at the very root of the app, and there is a possibility it can re-render itself because of changes in its ancestors, its value should be memoized.

[See example in codesandbox](https://codesandbox.io/s/part-7-1-memoize-context-provider-value-qgn0me?file=/src/App.tsx)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d2sfux1igu84ut22tyk7.png)

<h3>✅ Preventing Context re-renders: splitting data and API</h3>

If in Context there is a combination of data and API (getters and setters) they can be split into different Providers under the same component. That way, components that use API only won’t re-render when the data changes.

Read more about this pattern here: [How to write performant React apps with Context](https://www.developerway.com/posts/how-to-write-performant-react-apps-with-context)

[See example in codesandbox](https://codesandbox.io/s/part-7-2-split-context-data-and-api-r8lsws?file=/src/App.tsx)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ll9dh1bw1aybr2zjc1it.png)

<h3>✅ Preventing Context re-renders: splitting data into chunks</h3>

If Context manages a few independent data chunks, they can be split into smaller providers under the same provider. That way, only consumers of changed chunk will re-render.

Read more about this pattern here: [How to write performant React apps with Context](https://www.developerway.com/posts/how-to-write-performant-react-apps-with-context)

[See example in codesandbox](https://codesandbox.io/s/part-7-3-split-context-into-chunks-dbg20m?file=/src/App.tsx)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jxtx1soito2ju9j0vxls.png)

<h3>✅ Preventing Context re-renders: Context selectors</h3>

There is no way to prevent a component that uses a portion of Context value from re-rendering, even if the used piece of data hasn’t changed, even with `useMemo` hook.

Context selectors, however, could be faked with the use of higher-order components and `React.memo`.

Read more about this pattern here: [Higher-Order Components in React Hooks era](https://www.developerway.com/posts/higher-order-components-in-react-hooks-era)

[See example in codesandbox](https://codesandbox.io/s/part-7-4-context-selector-lc8n5g?file=/src/App.tsx)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/73w2pkixfwaqpdxisi50.png)

---

You can access the entire guide here:

<ul>
        <li>
          <a href="https://www.developerway.com/posts/react-re-renders-guide#part1">Part 1: what is re-render in React?</a>
        </li>
        <li>
          <a href="https://www.developerway.com/posts/react-re-renders-guide#part2">Part 2: when React component re-renders itself?</a>
        </li>
        <li>
          <a href="https://www.developerway.com/posts/react-re-renders-guide#part3">Part 3: preventing re-renders with composition</a>
        </li>
        <li>
          <a href="https://www.developerway.com/posts/react-re-renders-guide#part4">Part 4: preventing re-renders with React.memo</a>
        </li>
        <li>
          <a href="https://www.developerway.com/posts/react-re-renders-guide#part5">Part 5: improving re-renders performance with useMemo/useCallback</a>
        </li>
        <li>
          <a href="https://www.developerway.com/posts/react-re-renders-guide#part6">Part 6: improving re-renders performance of lists</a>
        </li>
        <li>
          <a href="https://www.developerway.com/posts/react-re-renders-guide#part7">Part 7: preventing re-renders caused by Context</a>
        </li>
      </ul>

---

Originally published at [https://www.developerway.com](https://www.developerway.com). The website has more articles like this 😉

[Subscribe to the newsletter](https://www.developerway.com), [connect on LinkedIn](https://www.linkedin.com/in/adevnadia/) or [follow on Twitter](https://twitter.com/adevnadia) to get notified as soon as the next article comes out.