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.
Creating a context
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.
Using the context
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}>
Adding a toggle
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, and let's connect!
Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter