2 min read

How to update context in React

Most examples showing how to use Context in React focus on reading a value in distant components. But how would you update the value?

const LanguageContext = createContext("en");

export const LanguageFlag = () => {
  const languageCode = useContext(LanguageContext);
  return <h1>Selected language code is {languageCode}</h1>;
};

const LanguageProvider = ({ children }) => {
  ...
  return (
    <LanguageContext.Provider value={language}>
      {children}
    </LanguageContext.Provider>
  );
};

Since context just helps you avoid passing down props by providing a "shortcut" to their values, you need to ask yourself - how would you update the value if you simply used props? You would just pass the setter as a prop! And this is also how you would update the value with context - here is the updated Provider:

const LanguageProvider = ({ children }) => {
  const [languageCode, setLanguage] = useState("en");
  return (
    <LanguageContext.Provider value={{ languageCode, setLanguage }}>
      {children}
    </LanguageContext.Provider>
  );
};

And the LanguageSwitcher that allows updating the value in the context:

export const LanguageSwitcher = () => {
  const { languageCode, setLanguage } = useContext(LanguageContext);
  return (
    <label>
      Pick your language:
      <select
        name="language"
        value={languageCode}
        onChange={(e) => setLanguage(e.target.value)}
      >
        <option value="en">English</option>
        <option value="fr">French</option>
        <option value="it">Italian</option>
      </select>
    </label>
  );
};

This is why people say "React context is not a state management solution" - because Context only gives you a "shortcut" for passing the props - what you pass is up to you - and in this case, it would be a state value and its updater. We are managing the state ourselves using useState. Depending on what you are trying to store, you might consider useReducer instead of useState.

You can check out the working code for this on CodeSandbox: https://codesandbox.io/p/sandbox/cool-almeida-2tmgmh


Is there all there is to it? Yes and no 😅
There are two caveats you need to be aware of:

Does your data come from the server?

For example the user profile details.
In that case, maybe it's best to simply use something like React Query, which is optimised for working with server state. It makes the code more readable and it takes care of caching, refreshing and invalidation for you.

Will you have a lot of components updating the state in context?

Then it might make sense to split your provider into a "data" provider and an "api" provider. This is because when using context, all consumers update, regardless of whether they read all the values from the context or not. So for example, if you had just one component reading the "language" and 10 components calling the setter - "setLanguage" - all 11 components would update, even if just one displays the value!
The official docs go over this pattern here as well: https://react.dev/learn/scaling-up-with-reducer-and-context

Get the React Practice Calendar!

28 days of focused practice of increasing difficulty, going through everything from Fundamentals, Data fetching, Forms and using Intervals in React.

You will also get notified whenever a new challenge is published.