Hey! I'm on a mission to make 100 React.js projects ending March 8th. Please follow my dev.to profile or my twitter for updates and feel free to reach out if you have questions. Thanks for your support!
Link to today's deployed app: Link
Link to the repo: github
This week I've been studying the Context API. This project used Context to share what is essentially a piece of appwide state- dark or light mode- across the React component tree.
The Context API
Let me take a quick moment to try and describe Context. There are alternatives to Context, and situations where you don't need it at all, but the gist of it is this: if you need a piece of state that can be optionally shared across any component in your React directory, and your React directory has multiple or many levels so that sharing a piece of state down the tree would be cumbersome, Context might be a good tool for you.
The ReactJS documentation describes an example where an avatar and username needs to be passed down multiple levels to a sub-component, like from index.js
to App.js
to Page.js
to Navbar.js
to Avatar.js
:
"It might feel redundant to pass down the user and avatarSize props through many levels if in the end only the Avatar component really needs it. It’s also annoying that whenever the Avatar component needs more props from the top, you have to add them at all the intermediate levels too."
In situations like this Context is a great tool.
Implementation
In my application we just had a couple of levels in the React tree. The App.js
component renders the following components: Navbar
and Main
. We have no need to display information about the theme in the main App component so it would be a bit annoying to have to pass it down through props, that's why we're using Context to share that information from index.js
through App.js
to Navbar
and Main
.
To handle Context we create a new JS file for all of the Context related bits, which are a part of the React package. We then pull out Provider
(this produces the context for use in the app) and Consumer
(this consumes the context from the producer wherever in the app you need it to).
The Consumer
part is easy- that's just a pure React component that we can feed some children later when we import it in other components. It's the Provider
part that requires more finesse. It's an actual component that has state (this is where the context is kept).
We give the component state for the piece of context you want to use, then use the Provider
component within the component's return. Lastly, Providers have a required prop called value that we use to pass data to the consumer.
import React from 'react';
const { Provider, Consumer } = React.createContext();
class ThemeContextProvider extends React.Component {
state = {
theme: 'dark',
};
toggleTheme = () => {
this.setState((prevState) => {
return {
theme: prevState.theme === 'light' ? 'dark' : 'light',
};
});
};
render() {
return (
<Provider
value={{ theme: this.state.theme, toggleTheme: this.toggleTheme }}
>
{this.props.children}
</Provider>
);
}
}
export { ThemeContextProvider, Consumer as ThemeContextConsumer };
As you can see from the example, if you want other components to be able to change the app-wide context, you also need to create a component method to change state, and pass that into the value
prop object as well.
Consuming Context
A Pacman-looking Consumer consumes some delicious React context
Later on, when we have a component that we want to provide context to, we simply import the Consumer
we created earlier and wrap the rest of the component in curly brackets to provide it as children to the Consumer
component.
In this example, my toggle is given both the theme context and the function we passed to the Provider to change state called toggleTheme
. When the user changes the toggle, we call this method.
import React from 'react';
import './ThemeToggle.css';
import { ThemeContextConsumer } from './themeContext';
function ThemeToggle() {
return (
<ThemeContextConsumer>
{(context) => (
<div className='toggle'>
<span className={`toggle-label ${context.theme}-theme-text`}>
Light Mode
</span>
<label className='switch'>
<input
type='checkbox'
checked={context.theme === 'dark'}
onChange={context.toggleTheme}
/>
<span className='slider round'></span>
</label>
<span className={`toggle-label ${context.theme}-theme-text`}>
Dark Mode
</span>
</div>
)}
</ThemeContextConsumer>
);
}
export default ThemeToggle;
Conclusion
Context is apparently a notoriously difficult thing to grasp so I, once again, highly recommend taking Scrimba's React bootcamp so that the wonderful Bob Ziroll can teach you. I've done my best. The only thing left is to pick the color scheme for the React Day theme. I chose the red color that Frontendmasters.com uses for their header because I like it, and found complementary colors from there. Pretty cool!
Here are the React docs for Context:
Context API React Docs
Top comments (0)