React Context Tutorial For Beginners
Tags: react, javascript, beginners, webdev
Published: 2021-11-10 16:41:50

---
title: React Context Tutorial For Beginners
published: true
date: 2021-11-10 14:43:44 UTC
tags: React,Javascript,beginner, webdev
canonical_url: https://blog.shahednasser.com/react-context-tutorial-for-beginners/
cover_image: https://blog.shahednasser.com/static/9ddfe0134aa1295aa6df113abfe30c23/ferenc-almasi-tvHtIGbbjMo-unsplash-2.jpg
---

_This article was originally posted on [my personal blog](https://blog.shahednasser.com/react-context-tutorial-for-beginners/)_

[Context](https://reactjs.org/docs/context.html) in React is one of the features that a lot of beginners stay away from because they find it complicated. The concept makes it sound like it's something advanced, however, when you learn it you'll realize that not only it's simple, but it will make your development simpler.

In this tutorial, you'll learn the basics of Contexts and how you can use them in your projects. We'll create a context to access the logged-in user in multiple components and pages.

You can find the code for this tutorial on [this GitHub repository](https://github.com/shahednasser/react-context-tutorial).

## Project Setup

In your terminal, use the following command to create a new React app:

```
npx create-react-app react-context-tutorial
```

Once the installation is done, go to the `react-context-tutorial` directory:

```
cd react-context-tutorial
```

Then, install the following dependencies which you'll use throughout the tutorial:

```
npm i axios react-bootstrap bootstrap@5.1.3 react-cookie react-router-dom
```

Here's what each dependency is for:

1. [axios](https://github.com/axios/axios): to send POST request to log in the user.
2. [bootstrap and react-bootstrap](https://react-bootstrap.github.io/getting-started/introduction): for easy styling
3. [react-cookie](https://www.npmjs.com/package/react-cookie): to store the user token in the cookies
4. [react-router-dom](https://reactrouter.com): to add pages and routing between them.

## Create the Context

You need to create the context next to be able to use it in your components. To create a context you can use `React.createContext` passing it the default value for that context.

In most cases, in the context's value you should have the object or variable you want to share between components and a setter function to change its value.

In the `src` directory, create the file `UserContext.js` with the following content:

```
import React from "react";

const UserContext = React.createContext({
  user: null,
  setUser: () => {}
});

export default UserContext;
```

This will create a context having as a default value an object that has the property `user`, which by default is `null`, and a property `setUser`, which by default is a function that does nothing. You also need to export the context to use it in components.

## Using the Context Provider

The next step to use a context is by using the Context Provider. The Provider is a  component that you should use at the highest level you want the context to be used in, and the children of that component will then have access to the context value.

In most cases, you'll add the Provider component at the very highest level of your app and all components will be children of that provider.

In this tutorial, you will put the provider in the `App` component which will render all the routes in the App.

Change the content of `src/App.js` to the following:

```
import 'bootstrap/dist/css/bootstrap.min.css';
import { useState } from 'react';

function App() {
    const [user, setUser] = useState(null);
    
    return (
    <UserContext.Provider value={{
      user,
      setUser
    }}>
    </UserContext.Provider>
  );
}

export default App;
```

First, you import the stylesheet for Bootstrap. This is for styling reasons only.

Then, inside the `App` component, you first define a `user` state variable and set its initial value to null.

In the returned JSX, you use the `UserContext.Provider` component. This is the context provider of `UserContext`. Every context created with `React.createContext` has this provider.

The provider takes a prop `value`, which is the value of the context. You pass it the `user` state variable created earlier and the `setUser` function to change the `user` state variable. This means that when other components use `setUser` function, the `user` state variable will change to the new value everywhere it's used.

## Add Navigation Component

You'll now add the `Navigation` component. This `Navigation` component will show the _Log In_ link when `user` is `null`, and will show the _Log Out_ link when the `user` is not `null`.

Create the file `src/components/Navigation.js` with the following content:

```
import { useContext } from "react";
import { Container, Nav, Navbar } from "react-bootstrap";
import { Link } from "react-router-dom";
import UserContext from "../UserContext";

export default function Navigation () {
  const {user, setUser} = useContext(UserContext);

  function logout () {
    setUser(null);
  }

  return (
    <Navbar bg="light" expand="lg">
      <Container>
        <Navbar.Brand href="/">React Context</Navbar.Brand>
        <Navbar.Toggle aria-controls="basic-navbar-nav" />
        <Navbar.Collapse id="basic-navbar-nav">
          <Nav className="me-auto">
            {!user && <Link to="/login">Log In</Link>}
            {user && <Nav.Link href="#" onClick={logout}>Log Out</Nav.Link>}
          </Nav>
        </Navbar.Collapse>
      </Container>
    </Navbar>
  );
}
```

Notice the usage of `useContext`. This is a React hook that lets you retrieve the value of a Context inside consumers, which are children of a context provider. So, all child elements of `UserContext.Providers`, including all of their children elements recursively, can use `useContext` to get the value of the context.

Here, you use `useContext` passing it the `UserContext` context to retrieve the `user` variable and `setUser` function. Then, based on the value of `user` you either show or hide the login and log-out links.

Notice the `logout` function, which is a handler of the `onClick` event of the log-out link. This function uses `setUser` to change the value of `user` to `null`, which will change the value everywhere it's being used or consumed.

## Add Home Page

Next, you'll create the Home component which will show on the Home page. This component does nothing special. It just shows the `Navigation` component and shows the user a message based on whether they're logged in or not.

Create `src/pages/Home.js` with the following content:

```
import { useContext } from "react";
import { Container } from "react-bootstrap";
import Navigation from "../components/Navigation";
import UserContext from "../UserContext";

export default function Home () {
  const {user} = useContext(UserContext);
  return (
    <>
      <Navigation />
      <Container>
        {!user && <h1>You're not logged in</h1>}
        {user && <h1>You're logged in with {user.token}</h1>}
      </Container>
    </>
  );
}
```

Here you also use the `useContext` hook to retrieve the `user`. Notice that you are only retrieving the  `user` and not `setUser` because you won't need it here.

If the `user` is `null`, the message "You're not logged in" will show, else the message "You're logged in with {user.token}" will show. The value of `user` here will change when any consumer of the context uses `setUser` to change the value.

## Add Home Route

After you've created the `Home` component, it's time to show it.

In `src/App.js` add the import for the `Home` component as well as the imports needed for routing from `react-router-dom` at the top of the file:

```
import {
  BrowserRouter as Router,
  Switch,
  Route
} from "react-router-dom";
import Home from './pages/Home';
```

Then, change the returned JSX to the following:

```
return (
    <UserContext.Provider value={{
    user,
    setUser
    }}>
    	<Router>
    		<Switch>
    			<Route path="/" component={Home} />
            </Switch>
		</Router>
	</UserContext.Provider>
);
```

Now, the `Home` component is a child of `UserContext.Provider` and subsequently it can access the context with its children using `useContext`.

If you run the server now:

```
npm start
```

You'll see a home page showing you that you're not logged in.

![React Context Tutorial For Beginners](https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-29-at-8.46.04-PM.png)

## Add Login Page

Now, you'll add the login page which will allow the users to log in. To simulate the login process, you'll use [Reqres](https://reqres.in), a fake REST API that lets you simulate a lot of requests including the user login request.

In the login page, you first need to check if the user is already logged in. If they are, you'll redirect to the home page.

If the user is not logged in then you'll show a form with email and password fields. When the user clicks the submit button, you send a request to Reqres' login API endpoint. Then, if the request is successful you set the logged-in user in the context.

Create the file `src/pages/LogIn.js` with the following content:

```
import axios from "axios";
import { useContext, useEffect, useRef, useState } from "react";
import { Form, Button } from "react-bootstrap";
import { useHistory } from "react-router";
import Navigation from "../components/Navigation";
import UserContext from "../UserContext";

export default function LogIn () {
  const [email, setEmail] = useState("george.bluth@reqres.in");
  const [password, setPassword] = useState("");
  const {user, setUser} = useContext(UserContext);
  const history = useHistory();
  const buttonRef = useRef(null);

  useEffect(() => {
    //check if user is logged in or not
    if (user !== null) {
      //redirect home
      history.push('/');
    }
  }, [history, user]);

  function handleSubmit (event) {
    event.preventDefault();
    buttonRef.current.disabled = true;
    
    //login user
    axios.post('https://reqres.in/api/login', {email, password})
    .then(({data}) => {
      //set token in local storage
      setUser({
        email,
        password,
        token: data.token
      });
    })
    .catch((err) => {
      console.error(err);
      alert('An error occurred, please try again later.');
      buttonRef.current.disabled = false;
    })
  }

  return (
    <>
      <Navigation />
      <Form onSubmit={handleSubmit} className="w-75 mx-auto">
        <h1>Log In</h1>
        <Form.Group className="mb-3" controlId="formBasicEmail">
          <Form.Label>Email address</Form.Label>
          <Form.Control type="email" placeholder="Enter email" required value={email} onChange={(event) => setEmail(event.target.value)} />
        </Form.Group>

        <Form.Group className="mb-3" controlId="formBasicPassword">
          <Form.Label>Password</Form.Label>
          <Form.Control type="password" placeholder="Password" required value={password} onChange={(event) => setPassword(event.target.value)} />
        </Form.Group>
        <Button variant="primary" type="submit" ref={buttonRef}>
          Submit
        </Button>
      </Form>
    </>
  )
}
```

Just as explained above, you have the `email` and `password` state variables to make the form inputs [controlled components](https://reactjs.org/docs/forms.html#controlled-components). Notice that the initial value of `email` is one of the emails for users available in Reqres.

You retrieve `user` and `setUser` from the context using `useContext`. You also use `useHistory` which is a [React Router hook](https://reactrouter.com/web/api/Hooks/usehistory) to get access to the `history` instance which you'll use to navigate.

In `useEffect`, which will run whenever the `user` or `history` variables change, you check if the user is logged in by checking if the value is null or not. If it's not null, it means the user is logged in so you navigate to the homepage using `history`.

Inside `handleSubmit`, which is the event listener for the form submit event, you send a POST request to Reqres' fake API endpoint to login. This endpoint returns a fake token to be used. If the request succeeds, you use `setUser` to set the user. Otherwise, you show an error.

The last thing left is to add the `LogIn` page as a route in `src/App.js`:

```
return (
    <UserContext.Provider value={{
    user,
    setUser
    }}>
    	<Router>
    		<Switch>
    			<Route path="/login" component={LogIn} />
        		<Route path="/" component={Home} />
            </Switch>
		</Router>
	</UserContext.Provider>
);
```

Now, run the server if it's not already running. Then, open the Log In page by clicking on the link in the navigation bar. You'll see a form with a prefilled email address.

![React Context Tutorial For Beginners](https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-29-at-11.04.57-PM.png)

You can enter any password you want then click _Submit_. Once the request is performed and the token is retrieved, you'll be redirected to the home page and the message for the logged in user will show.

![React Context Tutorial For Beginners](https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-29-at-11.07.58-PM.png)

Notice that the link in the navigation bar changed to show "Log Out" instead of "Log In". This is because the `user` variable passed through the context is updated everywhere it's being consumed. If you click on Log Out, the `user` variable will be `null` again.

## Use Cookies

When you log in a user you want to store their token in a cookie so that the next time they visit the website they're still logged in. In this section, you'll store the token in a cookie and set the initial value of the `user` state variable based on it.

In `src/App.js` add the following import at the beginning of the file:

```
import { useCookies } from 'react-cookie';
```

Then, change the definition of the `user` state to the following:

```
const [cookies] = useCookies();
const [user, setUser] = useState(cookies.token ? {token: cookies.token} : null);
```

The library `react-cookie` exposes the `useCookies` hook. Using this hook, you can retrieve the `cookies` object of cookies, where the properties are the name of each cookie.

If the cookie `token` is found, you set the initial value of `user` to the object `{token: cookies.token}`, else set it to `null`.

The next step is to set the cookie on login. In `src/pages/LogIn.js` add the import at the beginning of the file:

```
import { useCookies } from "react-cookie";
```

Then, change `setUser` in the fulfilment callback for the login request to the following:

```
setCookie('token', data.token);
setUser({
    email,
    password,
    token: data.token
});
```

The last step is to remove the cookie on log out. In `src/components/Navigation.js` add the import at the beginning of the file:

```
import { useCookies } from "react-cookie";
```

Then, inside `logout` function add the following line:

```
removeCookie('token');
```

If you test the website now, you can log in, close the tab then visit the website again and you'll still be logged in.

## Conclusion

In this tutorial, you learned how to use Context in React. It makes it so much easier to re-use data that you'll frequently use in different components without having to pass the variable and its setter through multiple components.