DEV Community

Random Dude
Random Dude

Posted on • Originally published at thetwilightcoder.com

The biggest pitfall of React Context - Unwanted re-render

Usually, in small apps, people create a global context to share state across the application.

In the following example,We have a global context:

import { createContext, useContext, useState } from 'react';

type ContextType = {
  stateOne: string;
  stateTwo: string;
  setStateOne: React.Dispatch<React.SetStateAction<string>>;
  setStateTwo: React.Dispatch<React.SetStateAction<string>>;
}

const GlobalContext = createContext<ContextType>({
 stateOne: '',
 stateTwo: '',
 setStateOne: () => null,
 setStateTwo: () => null,
});

export const GloBalProvider:React.FC<{children: React.ReactNode}> = ({ children }) => {
  const [stateOne, setStateOne] = useState('111');
  const [stateTwo, setStateTwo] = useState('222');

  return (
    <GlobalContext.Provider
      value={{
        stateOne, 
        setStateOne,
        stateTwo,
        setStateTwo
      } }
    >
      {children}
    </GlobalContext.Provider>
  );
};

export const useGlobalContext = () => useContext(GlobalContext);
Enter fullscreen mode Exit fullscreen mode

Using that context:

import { useEffect } from 'react';
import { GloBalProvider, useGlobalContext } from './GlobalContext';

const ChildOne = () => {
  const { stateOne, setStateOne } = useGlobalContext();
  useEffect(() => {
    console.log('TestContext ChildOne rerender');
  });

  return (
    <>
      <div>child one: {stateOne}</div>
      <button onClick={() => setStateOne('abc')}>change stateOne</button>
    </>
  );
};

const ChildTwo = () => {
  useGlobalContext();

  useEffect(() => {
    console.log('TestContext ChildTwo rerender');
  });

  return <span>child two</span>;
};

const TestContext = () => {
  return (
    <>
      <GloBalProvider>
        <ChildOne />
        <br />
        <ChildTwo />

      </GloBalProvider>
    </>
  );
};
Enter fullscreen mode Exit fullscreen mode

Let's run the code

When we change stateOne, we can see that the ChildTwo component re-renders even though it doesn’t use stateOne at all .

Even with React.memo wrapping around ChildTwo, it still doesn’t work.

That’s the problem with Context — every time a state inside the context changes, it triggers a re-render of every component that consumes the context.

Moreover, putting everything inside a global context in a large application will create a mess that’s really hard to maintain.

Conclusion: in a large application with complex data and flows, we should use a state management tool like Redux instead

Top comments (0)