Mastering React's Context

Mastering React's Context

A Guide to Efficient State Propagation using Context in React

ยท

4 min read

Hey There,

Welcome to the third post in this React Demystified series.


Last week, we looked into the useEffect hook and tried to understand why it's called that. And also, some fundamental questions like - What exactly is an effect?


This week, we dig into React's Context and the useContext hook. We will dig into the core of what we mean by Context and what is the significance of managing it throughout your React app. Let's do this! ๐Ÿ™Œ๐Ÿพ

Some context about Context

Why do you need context?

We looked at state in our first article in this series & found out that state is something that the UX was tightly coupled with. It was that data, which if changed, would require the UX displayed to the user to change as well.

So what is Context? According to the official docs, Context is primarily an alternative to passing props:

What is context

What does that mean? Well, I understand Context as this - It is that data which does not change frequently is relatively small in size and can be consumed anywhere in the entire application.

An example of Context

Let us say that there is some data that does not change frequently - Like the theme associated with a website. If we create the theme at the top, like the App component, and then want to use it in a button which was several layers deep, we would have to pass it down all the way.

Prop drilling

This is more commonly known as prop drilling.

The use of Context solves this problem. Because instead of passing the piece of data through all the components where it does not get used, we only need three touchpoints:

  • creation - Where the Context is created

  • updation - Where the Context value can be updated

  • consumption - Where the Context value can be read.

This #sketchnote below summarizes it well:

3 touchpoints of context

And that is what makes Context special. Because it provides us with an interface to tap into this context that is somehow magically available to us throughout the app.

Coding it up

With that theoretical understanding, let us now work with some code. We will look at it from the perspective of the 3 touchpoints discussed above.

Context creation

For creating Context we use the createContext function provided to us by React.

import { createContext } from 'react';

export const themeContext = createContext('light');

Notice how the created Context is exported out from this component. That is because in order to consume the Context in any child component, we would first have to import this exported variable (which we will see next).

Context consumption

Now, in order to consume the context value created without passing it down as props, we will need to import the above context variable and call the useContext hook that will return us the current value.

import { useContext } from 'react';
import { ThemeContext } from './App.js';

export default function Button({ children }) {
  const theme = useContext(ThemeContext);
  // ...
}

The above code runs and, theme gets the value of light, which was the default value set on the context.

But, you might wonder what was the need to do all this?

We can get the same result by just creating a constant named theme and exporting it from the App.js component. But that is where the next part comes into the picture.

Context modification with Provider

Anywhere down the component tree below the context creation, its value can be edited using the Provider component.

So, let us say we had a button to tweak the light and dark theme. If that button was tied to a state variable, the current value of the state variable that the button controls could be provided as the value for the provider:

import { ThemeContext } from './App.js';

export default function Main({ level, children }) {
  const [theme, setTheme] = useState('light');

  const toggleTheme = () => {
    setTheme(theme === 'light' ? 'dark' : 'light')
  }

  return (
    <section className="main">
      <LevelContext.Provider value={theme}>
        {children}
      </LevelContext.Provider>
      <Button /> // This button toggles theme
    </section>
  );
}

Once we have this in place if we try to read the Context value anywhere using useContext down the component tree inside of children, we will get the value that is set by this provider. Which in turn is being set via the button.

Hope that clears a lot of concepts related to Context in React and the useContext hook.

See you in the next one!

Cheers ๐Ÿ™Œ๐Ÿพ