React basics: explaining the useContext hook

I'm a full-stack developer from South Africa 🇿🇦. I love writing about JavaScript, HTML and CSS.
Search for a command to run...

I'm a full-stack developer from South Africa 🇿🇦. I love writing about JavaScript, HTML and CSS.
Very good point, I use this approach most of the time as well. Was just a bit clearer to explain without introducing custom hooks yet.
But super valid point!
Most of you know me for my consistency, a golden arrow in my blog series. I've written 1000 articles in 1008 days! Almost an article a day, and my honeymoon was the only holiday I ever took. I'm super proud of this achievement; it has been a fantasti...

It's not the first time I'll be talking about community. I think it's an essential aspect of any successful tool. This shows in my previous explorations of Astro, Medusa, and now Vendure as well. All these products thrive in a super open, welcoming, ...

The cool part about Vendure is how easy it is to set up and how abstract each layer is. Basically, we get the following elements: External database Server Worker Admin UI Frontend While this is amazing, it also brings a bit of complexity when it co...

The previous article looked at customizing Vendure on a data and process level. In this article, we'll look at customizing emails, as they are often a big part of a webshop system. We'll be looking at two different layers of customization for customi...

Even though Vendure is a pretty significant project out of the box, in some cases, we might want to go in and modify some elements to work to our specific use case. In this article, I'll take a high-level look at some elements we can customize within...

Sometimes we have data that we need to access in almost all parts of our components.
It will become a hassle to pass them down to each component, exactly where context comes in.
In this example, I'll use a specific theme for a website. Our website has a blue and a red theme, which the user can toggle based on their preferences.
Before we can do anything, we need to create a new context to wrap around our application.
So, let's look at how that works, create a new file called ThemeContext.js and start by adding the imports we need.
import { createContext, useState } from 'react';
Now let's define our themes, this is still pretty hardcoded, but it will work fine for this demo.
const themes = {
blue: {
background: 'blue',
color: 'white',
},
red: {
background: 'red',
color: 'black',
},
};
As you can see, we have a blue and a red theme.
The first thing we need to do now is create an actual context with a default value. In my case, I want the red theme to be the blue theme to be the default.
export const ThemeContext = createContext(themes.blue);
And then, we can export a ThemeProvider which helps us wrap this theme around our app.
export function ThemeProvider(props) {
return (
<ThemeContext.Provider value={themes.blue}>
{props.children}
</ThemeContext.Provider>
);
}
This provider can now be wrapped around our app to apply the context. Let's head over to our App.js file and do that.
import { ThemeProvider } from './context/ThemeContext';
function App() {
return (
<ThemeProvider>
<div className='App'>
The rest of our app
</div>
</ThemeProvider>
);
}
export default App;
This gives us access to anything in the theme.
Pretty cool, but how do we now use this context?
Create a sample component that will act as our paint. This component will take the context and display the correct color.
import { useContext } from 'react';
import { ThemeContext } from '../context/ThemeContext';
export default function Paint() {
const theme = useContext(ThemeContext);
return (
<div
style={{
background: theme.background,
color: theme.color,
padding: '2rem',
}}
>
I'm the paint
</div>
);
}
This component will render a simple div, with colors based on whatever our theme is.
Head back to your App and include this component.
import Paint from './components/Paint';
return (
<ThemeProvider>
<div className='App'>
<Paint />
</div>
</ThemeProvider>
);
You should now see the block in your browser like so:

If we now change our ThemeContext to be red, we should see a red box.
<ThemeContext.Provider value={themes.red}>

This is pretty exciting stuff already, but it becomes super powerful by adding a dynamic switch for our theme.
Let's say we want to render two buttons. Each button will set a different theme.
To do this, we first have to use useState in our ThemeContext file.
import { createContext, useState } from 'react';
export function ThemeProvider(props) {
const [theme, setTheme] = useState('blue');
const themeProviderData = {
theme: themes[theme],
setTheme: (theme) => setTheme(theme),
};
return (
<ThemeContext.Provider value={themeProviderData}>
{props.children}
</ThemeContext.Provider>
);
}
As you can see, I use the useState function to now set a basic theme (blue).
Then I create a primary object containing the current theme data and pass the setState function to modify the state variable.
Then we pass this object as the value of our theme.
One thing to note here is that we changed from passing a single variable to passing an object.
So head over to your Paint component and change the import like so:
const { theme } = useContext(ThemeContext);
Then we can go ahead and create a new component called Toggle.
import { useContext } from 'react';
import { ThemeContext } from '../context/ThemeContext';
export default function Toggle() {
const { setTheme } = useContext(ThemeContext);
return (
<>
<button onClick={() => setTheme('red')}>RED THEME</button>
<button onClick={() => setTheme('blue')}>BLUE THEME</button>
</>
);
}
As you can see, this function extracts the setTheme function from our context.
It then renders two buttons and appends this function with a specific value.
Go ahead and include this component in your App like so:
import Toggle from './components/Toggle';
function App() {
return (
<ThemeProvider>
<div className='App'>
<Paint />
<Toggle />
</div>
</ThemeProvider>
);
}
export default App;
And there we have it. We can now toggle between our two themes!

I've also added this project on GitHub if you want to see more details.
Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter