Alex Sidorenko

A Visual Guide to React Rendering - Context

August 19, 2021

This article is a 5th chapter of A Visual Guide to React Rendering.

When a component consumes context, and the value of this context changes, this component re-renders. But why does Component A and Component B also re-render in this example:

App structure is 'App (ContextProvider) > A > B > C'. Context Provider passes count state variable. Component C consumes context. Whenever count updates every component re-renders.

The components structure is App (ContextProvider) > A > B > C

const App = () => {
  // ...
  return (
    <AppContext.Provider ...>
      <ComponentA />
    </AppContext.Provider>
  )
}

const ComponentA = () => <ComponentB />
const ComponentB = () => <ComponentC />

Context and React rendering

From the first chapter, we know the default behavior of React rendering. When a component renders, React will recursively re-render all its children regardless of props or context. Let’s remove the context from our example and see this behavior in action.

App structure is 'App > A > B > C'. App stores state variable - count. Whenever count updates every component re-renders.

From the same chapter, we learned that to stop this recursive re-rendering, we can use memo. Let’s apply memo to the initial example.

App structure is 'App (ContextProvider) > A > B > C'. Context Provider passes count state variable. Component C consumes context. Component A wrapped with memo. Whenever count updates only App and Component C re-renders

Therefore 👇

Context and references

In real-life apps, we often need to pass more data to the context. Sometimes this data will rely only on certain specific state variables.

App structure is 'App (ContextProvider) > A > B > C'. App stores state variables: count, a, b. Context provider value is {a, b}. Component C consumes context. Component A wrapped with memo. Whenever count, a, or b updates all comopnents re-render

We pass a and b to the provider, but the consumer component re-renders even when count updates. How to prevent that?

Here is the hint - the text variable stores an object (non-primitive value). And… 👇

All consumers that are descendants of a Provider will re-render whenever the Provider’s value prop changes

React Docs - Context Provider

When we update the count value, the App component re-renders, leading to the redeclaration of the text variable. From the second chapter, we learned the difference between primitive and non-primitive values in javascript. We know that {a: "lorem", b: "ipsum"} !== {a: "lorem", b: "ipsum"} . It means that on every render of the App, the context value changes even if a and b don’t. And when the context value changes, the context consumer re-renders. To prevent that, we need to make sure that the text variable receives the same object reference. And from the third chapter, we know that we can do that with useMemo.

App structure is 'App (ContextProvider) > A > B > C'. App stores state variables: count, a, b. Context provider value is useMemo(() => ({a, b}), [a, b]). Component C consumes context. Component A wrapped with memo. Whenever count changes, Component C doesn't re-render

Now the text variable will only change when one of the values in useMemo dependency list changes. The count is not on the list. Therefore when the count changes, the text will get the previous reference, and the context consumer will not re-render.

Next chapter

A Visual Giude to React Rendering - DOM

Want to get better at modern React?

Subscribe to get one short article delivered to your inbox every week

One article a week. No spam.
Unsubscribe any time