Design+Code logo

Quick links

Suggested search

CodeSandbox link

You can find the full code for this tutorial at https://codesandbox.io/s/usecontext-hook-4rf8u.

Create the Context

First, let's create a new file called ThemeContext.js. As the name says, this context will allow us to share the theme state across the entire application. At the top of the file, we'll need to import a few things, that we'll be using later on.

// ThemeContext.js

import React, { useState, createContext, useContext } from "react";

Next, let's create an object called themes. This will allow us to define different colors for both the light and dark themes. Don't forget to export the themes object, as we'll need it outside of this file.

// ThemeContext.js

export const themes = {
  light: {
    foreground: "#000000",
    background: "#eeeeee"
  },
  dark: {
    foreground: "#ffffff",
    background: "#222222"
  }
};

Then, let's create another object called initialState. As the name says, it'll be the initial state of the application, when the user lands on our application. This object contains the default theme, which will be light, and the setTheme function, which will be an empty callback function for the moment.

// ThemeContext.js

const initialState = {
  theme: themes.light,
  setTheme: () => {}
};

Now that we have the initial state, we can create our context using the createContext function from React. This function requires an initial state, so let's pass it as an argument. We'll also save the result of createContext in a ThemeContext variable.

// ThemeContext.js

const ThemeContext = createContext(initialState);

Create the Provider

A Provider allows all its children component to subscribe to the context's changes. This provider accepts children as an argument. Inside of it, we're using useState in order to set the theme. The ThemeContext.Provider accepts one prop, which the value prop. Everything passed to the value prop will be accessible to all its children. Remember to export the ThemeProvider, as we'll need it outside of this file.

// ThemeContext.js

export const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState(themes.light);
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

Create the useContext

Let's create a custom hook called useTheme. Inside of this custom hook, we'll be using the useContext hook, that allows us to access both the theme and the setTheme function outside of this file. If useContext fails to create a context, it'll return undefined because we forgot the wrap our App or component in a ThemeProvider. If everything works fine, we'll return the actual context. Finally, don't forget to export default our custom useTheme hook.

// ThemeContext.js

const useTheme = () => {
  const context = useContext(ThemeContext);

  if (context === undefined) {
    throw new Error("useTheme must be used within a ThemeProvider");
  }
  return context;
};

export default useTheme;

Add Provider to the App

Let's go to our App.js file. In here, we'll import ThemeProvider from the ThemeContext file.

// App.js

import { ThemeProvider } from "./ThemeContext";

Wrap the entire content of the return body in a ThemeProvider. This will allow us to share the theme state across the entire application.

// App.js

export default function App() {
  return (
    <ThemeProvider>
      {/* Entire content here... */}
    </ThemeProvider>
  );
}

Create a Button

Let's test out this useContext in a button component. First, create the component. Don't forget to add your component in your App.js file.

// Button.js

import React from "react";
import styled from "styled-components";

const Button = () => {
  return <StyledButton>I am styled by theme context!</StyledButton>;
};

export default Button;

const StyledButton = styled.button`
  background: #eeeeee;
  color: #000000;
  padding: 12px;
  border: none;
  border-radius: 30px;
  font-weight: bold;
  font-family: Segoe UI, sans-serif;
  display: grid;
  justify-self: center;
  cursor: pointer;
`;

Next, import the useTheme hook and the themes object from ThemeContext.js.

// Button.js

import useTheme, { themes } from "./ThemeContext";

Inside of your component, access the theme and the setTheme function from the useTheme hook, like so:

// Button.js

const Button = () => {
	const { theme, setTheme } = useTheme();

	// Return body here...
}

Let's style our button depending on the set theme. We'll pass two props to our button component, a color and a background.

// Button.js

<StyledButton
  color={theme.foreground}
  background={theme.background}
>
  I am styled by theme context!
</StyledButton>;

In the styling of the button below our component, let's use these props and set it as our button's foreground and background colors.

// Button.js

const StyledButton = styled.button`
  background: ${(props) => props.background};
  color: ${(props) => props.color};
	/* More styling... */
`;

Let's add an onClick event to our button in order to toggle the theme from light to dark and back again.

// Button.js

onClick={() =>
  setTheme(theme === themes.light ? themes.dark : themes.light)
}

Now, when you click on your button, you'll see that the text and background colors are toggling from light to dark mode!

Create a Subtitle component

Right now, we're using useContext in order to style our button. However, it's a single component and we could've used a local state instead. Let's take it a step further to see how useContext can share state across different components. Let's create a subtitle component that'll let the user know the current theme.

// Subtitle.js

import React from "react";
import styled from "styled-components";

const Subtitle = () => {
  return (
    <MySubtitle>
      My current theme is light.
    </MySubtitle>
  );
};

export default Subtitle;

const MySubtitle = styled.p`
  color: black;
  font-weight: bold;
  font-family: Segoe UI, sans-serif;
`;

Import useTheme.

// Subtitle.js

import useTheme from "./ThemeContext";

Access the theme object from the useTheme hook.

// Subtitle.js

const { theme } = useTheme();

In the text of our Subtitle, we'll check if the current theme is light or dark, and display the text accordingly.

// Subtitle.js

<MySubtitle>
  My current theme is {theme.background === "#eeeeee" ? "light" : "dark"}
</MySubtitle>;

Now, every time you toggle the theme with the button, you'll also see the Subtitle component being updated in real-time. Isn't it amazing?

Learn with videos and source files. Available to Pro subscribers only.

Purchase includes access to 50+ courses, 320+ premium tutorials, 300+ hours of videos, source files and certificates.

BACK TO

useOnScreen hook

READ NEXT

Fragments

Templates and source code

Download source files

Download the videos and assets to refer and learn offline without interuption.

check

Design template

check

Source code for all sections

check

Video files, ePub and subtitles

Videos

ePub

Assets

Subtitles

1

Intro to React Hooks

An overview of React Hooks and the frameworks you can use to build your React application blazingly fast

3:39

2

Create your first React app

Create your first React project from the Terminal and save it on your local computer

4:23

3

React Component

Create your first JSX component using React

2:54

4

Styling in React

How to style your React components using inline styling, separate stylesheets or styled-components

5:06

5

Styles and Props

Render different styles depending on different properties passed to your component

2:22

6

Understanding Hooks

Learn about the basics of React Hooks, which introduced at React Conf 2018

3:21

7

useState Hook

Use the useState hook to manage local state in your React component

2:54

8

useEffect Hook

Manage with your component's lifecycle with the useEffect hook

3:41

9

useRef Hook

Learn about the useRef hook, which replaces the JavaScript getElementById way

3:00

10

Props

Learn about props in React to pass data from parent to child components

3:11

11

Conditional Rendering

Render different UIs depending on different conditions and states

4:21

12

Load Local Data

Load local JSON data into your React application

4:04

13

Fetch Data from an API

Learn the basics of asynchronous functions and promises by fetching data from an API using fetch, useEffect and useState

5:40

14

Toggle a state

Learn how to toggle a state from true to false and back again

4:05

15

useInput Hook

Create a hook to get the value and the onChange event of input fields

6:04

16

Gatsby and React

Create a static content-oriented website using React on Gatsby

6:44

17

NextJS and React

Create your first NextJS React application

5:24

18

React TypeScript Part 1

Learn how to create a React TypeScript application using the Create React App, Gatsby and NextJS methods

8:19

19

React TypeScript Part 2

Learn the basics of TypeScript and how to use TypeScript in a React component

7:35

20

useScrollPosition Hook

Create a custom hook to listen to the current window position of the user

4:26

21

useOnScreen hook

Create a custom hook to listen to when an element is visible on screen

8:08

22

useContext Hook

Manage global states throughout the entire application

8:32

23

Fragments

Group multiple children together with React Fragments

2:43

24

Lazy Loading

Lazy Load heavy components to improve performance

4:05

25

React Suspense

Wait for data with React Suspense and React.lazy

3:13

26

Environment Variables

Make environment variables secret with a .env file

4:43

27

Reach Router

Create a multiple-pages React application with Reach Router

5:31

28

URL Params

Create unique URL with URL Params

4:04

29

SEO and Metadata

Optimize a React application for search engines with React Helmet

6:47

30

Favicon

Add an icon to a React website

3:03

31

Dynamic Favicon

Change the favicon's fill color depending on the user's system appearance

2:14

32

PropTypes

Implement props type-checking with PropTypes

3:54

33

Custom PropTypes

Create a custom PropType using a validator function

3:58

34

useMemo Hook

Prevent unnecessary re-renders when the component stays the same

4:05

35

forwardRef Hook

Forward a ref to a child component

3:28

36

Handling Events

How to handle events in React

5:44

37

Spread attributes

Learn how to make use of the spread operator

3:35

38

useMousePosition Hook

Detect the user's mouse position on a bound element

4:55

39

useReducer with useContext Part 1

Create a reducer to be used in a context

7:33

40

useReducer with useContext Part 2

Incorporate useReducer with useContext

6:48

41

useReducer with useContext Part 3

Connect the context and reducer with the frontend

5:43

42

Netlify

Deploy to production using Netlify

5:08

43

Gatsby Cloud

Deploy to production using Gatsby Cloud

6:19

44

Gatsby Plugin Image

Use gatsby-plugin-image for automatic image resizing, formatting, and higher performance

8:11

45

useOnClickOutside Hook

Toggle a modal visibility with a useOnClickOutside hook

6:32

46

useWindowSize Hook

Create a hook to determine the width and height of the window

4:14

47

usePageBottom hook

Detect if the user scrolled to the bottom of the page

4:48

48

useLocalStorage Hook

Store an item in a browser's local storage

5:27

49

Three.js in React Part 1

Bring your website to life with beautiful 3D objects

17:33

50

Three.js in React Part 2

Bring your website to life with beautiful 3D objects

11:18