DEV Community

Cover image for Context and the useContext hook.
Tallan Groberg
Tallan Groberg

Posted on

Context and the useContext hook.

image from https://www.udemy.com/course/react-hooks-tutorial/

In this tutorial we are going to be making a basic app with context so that the user can enjoy dark mode in your react app.

Why is this helpful?

this is helpful because context allows you to scale your applications without having to pass props between components that don't need them.

As it stands this is the simplest way I have come across to make context.

How you should use this tutorial?

you should try and go through this tutorial with as little referencing as possible. Come up with your own way of setting up context using hooks, then practice until you can do this from memory.

prerequisites:

  1. basic knowledge of javascript

  2. basic knowledge of react

  3. create react app installed globally on your computer.

  4. a text editor, I use VS code.

getting started.

create a new react app by running this command in your command-line.

create-react-app use-context-tutorial

Enter fullscreen mode Exit fullscreen mode

open the folder.

cd use-context-tutorial

Enter fullscreen mode Exit fullscreen mode

open it in your text editor.

code .

Enter fullscreen mode Exit fullscreen mode

make sure that you have the react boiler plate by starting the app.

npm start

Enter fullscreen mode Exit fullscreen mode

after you have verified that everything is working by a the react logo appearing.

Alt Text

in your src folder make another folder called providers

you can do this by right clicking the src if you are using vscode then click the new folder option.

inside the providers folder make an new file called ThemeProvider.js

in your ThemeProvider.js you are going to make an exported const containing the react context object and the ThemeProvider function so that we can start declaring theme as a piece of state.

start by importing react at the top of the file.

import React from 'react';

Enter fullscreen mode Exit fullscreen mode

then make make a variable for the context to live and make it equal to React.createContext() by adding this line.

export const themeContext = React.createContext()

Enter fullscreen mode Exit fullscreen mode

Now make a function that we can have state and put the themeContext.Provider with value object in the return for the ThemeProvider function.

we are going to need props for the ThemeProvider as well.

you should have a function that looks like this.

const ThemeProvider = (props) => {
  return (
    <themeContext.Provider value={{

    }}>

    </themeContext.Provider>
  );
};

export default ThemeProvider;

Enter fullscreen mode Exit fullscreen mode

notice that the value prop on the Provider has 2 sets of curly brackets. this is because you are breaking out of JSX for the first, then going into object notation for the second.

between the opening and closing brackets for the Provider we are going to add the consumer

we need to add state to this function so this is a perfect job for useState.

import useState at the top.

import React, {useState} from 'react';

Enter fullscreen mode Exit fullscreen mode

now add the state for the theme and set the initial state to 'light'

const [theme, setTheme] = useState('light')

Enter fullscreen mode Exit fullscreen mode

add the theme inside of the value for the Provider.

Between the opening and closing angle brackets on the Provider, add the props.children object inside curly brackets.

the whole file should look like this.

import React, {useState} from 'react';

export const themeContext = React.createContext()

const ThemeProvider = (props) => {
  const [theme, setTheme] = useState('light')

  return (

    <themeContext.Provider value={{
      theme
    }}>
      {props.children}
    </themeContext.Provider>
  );
};

export default ThemeProvider;

Enter fullscreen mode Exit fullscreen mode

notice that even though we put the theme inside of an object this will still be valid javascript. this is because it is considered an object literal

we are done in this file. Go to the index.js file so that we can wrap the app component with the provider.

first import the ThemeProvider like this.


import ThemeProvider from './providers/ThemeProvider'
Enter fullscreen mode Exit fullscreen mode

then make an app sandwich with some ThemeProvider bread like this.

ReactDOM.render(
  <ThemeProvider>
    <App />
  </ThemeProvider>

, document.getElementById('root'));

Enter fullscreen mode Exit fullscreen mode

now everything inside of your application should have access to your context.

to test it out, go to your App.js and set up the theme.

first we need to import the useContext hook inside the App.js

import React, {useContext} from 'react';

Enter fullscreen mode Exit fullscreen mode

we also want the theme context in this component.

import { themeContext } from './providers/ThemeProvider';

Enter fullscreen mode Exit fullscreen mode

between the lines for function App() and return we want to grab the theme with the useContext hook.

  const {theme} = useContext(themeContext)
Enter fullscreen mode Exit fullscreen mode

now add a console.log for the theme

console.log('theme', theme)
Enter fullscreen mode Exit fullscreen mode

if your local server is still on and you did everything correctly, when you open your dev tools you should see something like this...

Alt Text

just to be sure here is the whole App.js


import React, {useContext} from 'react';
import logo from './logo.svg';
import './App.css';
import { themeContext } from './providers/ThemeProvider';

function App() {

  const {theme} = useContext(themeContext)

  console.log('theme', theme)


  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;


Enter fullscreen mode Exit fullscreen mode

now we can change our theme with click events.

to do that go back to your themeProvider and add setTheme to your Providers value object the same way you added the theme.

return (
    <themeContext.Provider value={{
      theme,
      setTheme
    }}>
      {props.children}
    </themeContext.Provider>
  );

Enter fullscreen mode Exit fullscreen mode

don't forget the comma. ,,,

in the App.js add the setTheme inside the curly brackets to add it to the available objects from the themeContext.

const {theme, setTheme} = useContext(themeContext)

Enter fullscreen mode Exit fullscreen mode

grabbing things from themeContext

make a button under the learn react link.

 <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
        <button >change theme</button>

Enter fullscreen mode Exit fullscreen mode

now we can make a new string populate the theme state in the ThemeProvider from the App.js.

to do this, add an onClick event with the setTheme making the new string 'dark'.

<button onClick={() => setTheme('dark')}>change theme</button>

Enter fullscreen mode Exit fullscreen mode

you could change theme to a boolean to make it so that you can switch back and forth but that is a challenge I leave up to you.

now we can add inline style to make the background color change on the click event.

on the div right below the return add this style attribute.

<div style={theme === 'dark' ? {backgroundColor: "#000000"} : null} >

Enter fullscreen mode Exit fullscreen mode

it still doesnt work when you click it.

there is css over riding your styles from the header attribute.

delete the className on the header to solve the problem.

  <header>

Enter fullscreen mode Exit fullscreen mode

everything should be working and I know you can make it prettier that I have here but the main point was to learn about context.

You can really make this your own from here.

see the github

Top comments (0)