Optimize React Context Step-by-step in 4 examples
Tags: javascript, webdev, react, nextjs
Published: 2023-03-24 21:21:46

When using React components in combination with `Context`, you can optimize rendering by wrapping your React component with React.memo right after your context provider. This will prevent unnecessary re-renders.

Here are some examples of how re-rendering works with `Context`:

---

## Example 1:

```javascript
// App (ContextProvider) > A > B > C

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

const ComponentA = () => <ComponentB />;
const ComponentB = () => <ComponentC />;
const ComponentC = () => null;
```
In this example, if the `App` component re-renders, all components within it will also re-render, regardless of whether or not their `props` have changed.



## Example 2:
To prevent the re-rendering of all `ComponentA`, `ComponentB`, and `ComponentC` if the App component re-renders, you can use `React.memo` as follows:
```javascript
// App (ContextProvider)

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

const ComponentA = React.memo(() => <ComponentB />);
const ComponentB = () => <ComponentC />;
const ComponentC = () => null;
```


## Example 3:
```javascript
// App (ContextProvider) -> C

const App = () => {
  const value = {a: 'hi', b: 'bye'};
  return (
    <AppContext.Provider value={value}>
      <ComponentA />
    </AppContext.Provider>
  );
};

const ComponentA = React.memo(() => <ComponentB />);
const ComponentB = () => <ComponentC />;
const ComponentC = () => {
  const contextValue = useContext(AppContext);
  return null;
};
```
In this example, even though the provider value doesn't seem to change, `ComponentC` gets re-rendered. This is because, in JavaScript, the below assertion is `true`:

`{a: 'hi', b: 'bye'} !== {a: 'hi', b: 'bye'}`


## Example 4:
The problem in Example 3 can be resolved by using the useMemo hook from React as follows.
```javascript
// App (ContextProvider)

const App = () => {
  const a = 'hi';
  const b = 'bye';
  const value = useMemo(() => ({a, b}), [a, b]);

  return (
    <AppContext.Provider value={value}>
      <ComponentA />
    </AppContext.Provider>
  );
};

const ComponentA = React.memo(() => <ComponentB />);
const ComponentB = () => <ComponentC />;
const ComponentC = () => {
  const contextValue = useContext(AppContext);
  return null;
};
```

With this implementation, if the App re-renders for any other reason that does not change any of the 'a' or 'b' values, the sequence of re-renders will be as follows:

`App (ContextProvider)`

This results in the desired outcome of avoiding an unnecessary re-render of `ComponentC`. By using `useMemo`, the same object reference for the `value` variable is guaranteed. Since this variable is assigned to the provider's `value`, the context is determined to be unchanged, and no consumers are notified.

---

### Summary:
This blog post provides information on optimizing rendering when using React components with Context by using React.memo. It includes examples of how re-rendering works with Context and how to prevent unnecessary re-renders using React.memo.