preview image

July 2022

Using React Context for managing global State

There are seemingly infinite ways to manage state in React. You can embrace the boilerplate and use redux, you can use one of the newer and maybe simpler libraries, like jotai or zustand and probably be fine.

But sometimes, you just want to store simple values that you can access globally using a Hook. Or maybe you just don't want to add another library to your 300MB bundle. Whichever it is, by using React Context with TypeScript, you can create a pretty simple way of managing your global state.

I've included a simple example showing you how to use the context API for storing the current theme, accessible from anywhere.

You can also enter your own context name, e.g. Auth, Connection, Locale, etc. and it will generate the boilerplate code for you.


import React, { createContext, useContext, useEffect, useState } from "react";

interface ThemeData {
  isDarkmode: boolean;
  setIsDarkmode(isDarkmode: boolean): void;
}

// @ts-ignore
const ThemeContext = createContext<ThemeData>();

export function ThemeProvider({
  children,
}: {
  children: React.ReactNode[] | React.ReactNode;
}) {
  const value = useThemeData();
  return <ThemeContext.Provider value={value}>
    {children}
  </ThemeContext.Provider>;
}

export const useTheme = () => {
  return useContext(ThemeContext);
};

function useThemeData(): ThemeData {
  const [isDarkmode, setIsDarkmode] = useState(false);

  return {
    isDarkmode,
    setIsDarkmode,
  };
}

You need to wrap a component in the context before you can access it. If you want to access it in every component, place it above all else in your component hierarchy, e.g. in your App.tsx:

import React from "react";
import Button from "Button";
import { ThemeProvider } from "./ThemeProvider";

export default function App() {
  return (
    <ThemeProvider>
      <Button />
    </ThemeProvider>
  );
}

Then you can use it in any child component of App.tsx, e.g. a button:

import React from "react";
import { useTheme } from "./ThemeProvider";

export default function Button() {
  const { isDarkMode } = useTheme();

  return <button data-is-darkmode={isDarkMode}>Hello</button>;
}