Project 24 / 100 - Dark and Light Mode CRA with the React Context API
Tags: react, javascript, css, 100daysofcode
Published: 2020-12-29 19:27:14

*Hey! I'm on a mission to make 100 React.js projects ending March 8th. Please follow my dev.to profile or my [twitter](https://www.twitter.com/jwhubert91) for updates and feel free to reach out if you have questions. Thanks for your support!*

Link to today's deployed app: [Link](https://100-react-project-day-24-dark-mode-context-api.netlify.app/)
Link to the repo: [github](https://github.com/jwhubert91/100daysofreact/tree/master/day-24-dark-mode-context-api)

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
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1t338waoffcjqpiwpq8j.jpg)
######_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](https://reactjs.org/docs/context.html)