DEV Community

Cover image for Optimize React Context Step-by-step in 4 examples
Mahdi Ta'ala
Mahdi Ta'ala

Posted on • Originally published at Medium

Optimize React Context Step-by-step in 4 examples

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
};
Enter fullscreen mode Exit fullscreen mode

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;
};
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)