Optimize React Context Step-by-step in 4 examples

Mahdi Taala
2 min readMar 19, 2023

--

Photo by Rahul Mishra on Unsplash

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:

// 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:

// App (ContextProvider)

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

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

Example 3:

// 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.

// 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.

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.

--

--

Mahdi Taala

Front-End Developer · JavaScript | TypeScript | ReactJS | NextJS