Project 62 of 100 - Simplify Context components with the useContext() Hook in React
Tags: react, javascript
Published: 2021-04-27 13:30:08

*Hey! I'm on a mission to make 100 React.js projects ending May 31st. 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-projects-day-62-usecontext.netlify.app/)
Link to the repo: [github](https://github.com/jwhubert91/100daysofreact/tree/master/day-62-useContext-theme-switcher)

Way back in December I published this simple project that was all about using the React context API by extending React's pre-build components ((link to project)[https://dev.to/jwhubert91/project-24-100-dark-and-light-mode-cra-with-the-react-context-api-3e4k]).

Today I'm going back to Context and creating something similar. It's a UI theme switcher using context- this time using hooks instead of class components.

##useContext()
As a part of the relatively newer React approach of phasing out React class components, we need to learn the React hooks way to extend basic React functionality like Context or state. There is the added advantage that it also looks better.

In this project we have our `App` component, a `Button` component and a `Header`. All we're going to do is switch between light mode and dark mode in your application and React's Context API is a great way to achieve this.

When using the `useContext()` hook we don't have to extend class based components. Like in project 24 we need to create a pure React component to house our context provider and to instantiate the Context API. We use this component to then export the context and context provider anywhere else in the application.

```
import React, {useState} from 'react'
const ThemeContext = React.createContext();

function ThemeContextProvider(props) {
  const [theme,setTheme] = useState("dark")

  const toggleTheme = () => {
    setTheme(prevTheme => prevTheme === "light" ? "dark" : "light")
  }

  return (
    <ThemeContext.Provider value={{theme,toggleTheme}}>
      {props.children}
    </ThemeContext.Provider>
  )
}

export {ThemeContextProvider,ThemeContext}
```

Above we create an instance of React's context then assign it to the variable ThemeContext. We then create state on this component with the `useState` hook and store a variable `theme` in state. We also create a method on this functional component called `toggleTheme()` that switches the state of this component.

As in our class component Context example, we use the Provider property on our instantiated context `ThemeContext` and use its pre-built `value` prop to store the theme state variable and toggleTheme method from this functional component.

You can then *provide* that context to any other part of your application but typically you want it pretty high up in the component hierarchy so that more of your application has access to this context. We put it as high up as it gets in the `index.js` file. This is the same with our without useContext, since it's just importing the provider and wrapping the application in it.

```
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import {ThemeContextProvider} from './themeContext';

ReactDOM.render(
  <ThemeContextProvider>
    <App />
  </ThemeContextProvider>,
  document.getElementById('root')
);
```

##Consuming Context with useContext()
Remember that the cool thing about Context is that you really don't need to pass anything down to lower level components with props as long as a provider for that context is positioned higher up the component tree. Since we've done that, our `App` component doesn't have any mention of context despite the fact that we know we're going to consume data from it lower down in `Button` and `Header`.

```
import React from 'react';
import Header from './Header';
import Button from './Button';

function App() {
  return (
    <div className="App">
      <Header  />
      <Button />
    </div>
  );
}

export default App;
```

To actually consumer the context we go directly into the components where we want to use it. Let's start with Header since it's purely a UI change.

```
import React, {useContext} from "react"
import {ThemeContext} from "./themeContext"

function Header(props) {
    const {theme} = useContext(ThemeContext)
    return (
        <header className={`${theme}-theme`}>
            <h2>{theme === "light" ? "Light" : "Dark"} Theme</h2>
        </header>
    )    
}

export default Header
```

To consume our theme data from `ThemeContext` we simply bring in the `useContext` React hook then store the exported theme in a variable in the functional component, above the return. We import the ThemeContext and then can use `useContext()` to specify which context we want to use:

```
const {theme} = useContext(ThemeContext)
```

Since we've destructured the `theme` variable out, we can now use it like any other variable in our component. We will use it to send data about which theme (light or dark) we have stored in context for the app and change the className of the `header` accordingly. In our CSS the two classes have different colors associated with them:

```
.dark-theme {
  background-color: #333333;
  color: whitesmoke;
}

.light-theme {
  background-color: whitesmoke;
  color: #333333;
}
```

In our `Button` component we also consume the theme context but will import a function into the button as well, to toggle the theme.

```
import React, {useContext} from "react"
import {ThemeContext} from "./themeContext"

function Button(props) {
    const {theme, toggleTheme} = useContext(ThemeContext)
    return (
        <button 
            onClick={toggleTheme} 
            className={`${theme}-theme`}
        >
            Switch Theme
        </button>
    )    
}

export default Button
```

This syntax is a lot more clean than wrapping the button component in a Consumer component as in my earlier project using context.

The button now toggles the theme throughout the application and we did it by using data from the themeContext functional component and a little `useContext()`. Pretty easy! I'm definitely loving React Hooks.

**If you like projects like this and want to stay up to date with more, check out my Twitter [@jwhubert91](https://twitter.com/jwhubert91), I follow back! See you tomorrow for another project, this time on custom hooks.**