Keeping track of React state with useContext()
Tags: javascript, tutorial, beginners, react
Published: 2022-10-06 02:01:34

<a id="top"></a>In my time learning React at [Flatiron School](https://flatironschool.com/about-us/), I came to really like the [useContext hook](https://reactjs.org/docs/context.html). I remember at first, though, the concept of context was a little confusing. 

I'm excited to share what I've learned, and I hope it helps you.

## Table of Contents
* [What is _useContext_?](#what)
* [Example for setting up _useContext_](#example)
    * [Make a context file](#make)
    * [Wrap Provider around highest level component](#wrap)
    * [Using _useContext_](#using)
* [Conclusion](#conclusion)

This article walks through how to set up and use a Context component in a React application, using functional component syntax. This article assumes you know the basics of React, and moves past some concepts quickly. Note the links abound for elaboration, if you'd like to dig deeper into React Context.

It's [important to understand](https://reactjs.org/docs/thinking-in-react.html) how hooks, props & state works with functional components before you dive into using context to control global state.

## A couple brief definitions to warm us up:
* [Hooks:](https://reactjs.org/docs/hooks-overview.html) functions that let you “hook into” React state and lifecycle features from function components.
* [Props:](https://reactjs.org/docs/components-and-props.html) arbitrary properties that are passed down from parent to child components.
* [State:](https://www.digitalocean.com/community/tutorials/how-to-manage-state-on-react-class-components) the structure that keeps track of how data changes over time.

---

## What is _useContext()_?<a id="what"></a>
[(back to top)](#top)

The **useContext** hook is a way to manage global state without needing to pass state as props. When your component tree starts to grow, you might notice certain state that you need among sibling components, like a student's id or items in a cart. 

One solution might be to move that state to the nearest parent component, but that might be all the way up to the App component, and you might have to [prop-drill](https://www.geeksforgeeks.org/what-is-prop-drilling-and-how-to-avoid-it/) to manage that state. 

![Basic Component Tree](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aoo1ry0d3c79v7q2nijc.png)

A better solution might be to [re-compose](https://www.youtube.com/watch?v=3XaXKiXtNjw) the structure of your component tree and pass state as props, but that might not be a reasonable solution depending on the complexity of your app.

This is where useContext() might come in handy. By keeping track of state in context & passing that context to the components can make your life a whole lot easier.

![Component tree with context](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y18jgs2jtxp8k5j782vd.png)

---

## Example for setting up _useContext()_<a id="example"></a>
[(back to top)](#top)
[(skip to see result)](#result)

If you'd like to follow along, make sure you have a text editor and command line prompt handy. 

Create a new React App called whatever you want, like "student-library".

``` 
npx create-react-app student-library
cd student-library
npm start
```

## 1. Make a context file<a id="make"></a>
[(back to top)](#top)

Let's say we're trying to keep track of & update data about hypothetical students in our app.

Let's start writing code. Here's how I like to structure my files in my React App.

![File Structure for React App](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oz92bkgpxcxdsajem5a4.png)

---

i. From your app's '`/src`', folder, create a folder called '`/context`', then from there make a file called "`StudentContext.jsx`".

---

ii. At the top of the file, import React, and start a function component called `StudentProvider`.

```
import React from "react";

function StudentProvider() {}
```

---

iii. Now, use the [`createContext()`](https://contactmentor.com/react-createcontext-example/) function built into React to create a Context object. 
Outside of/above the function declaration, make StudentContext:

```
const StudentContext = React.createContext();
```

As [React Docs](https://reactjs.org/docs/context.html) say, 

> Every Context Object comes with a Provider React component that allows consuming components to subscribe to context changes.
 

We will use this Provider in the next steps to give other components access to our context's state.

---

iv. Return `StudentContext.Provider` inside the function component, wrapped around the special [`children`](https://www.netlify.com/blog/2020/12/17/react-children-the-misunderstood-prop/) props.

```
function StudentProvider({ children }) {
  return (
    <StudentContext.Provider>
      { children }
    </StudentContext.Provider>
  )
}
```

---

v. At the end of the file, export `StudentContext` and `StudentProvider`.

```
export { StudentContext, StudentProvider }
```

---

vi. Now, set up the student's state. Import the `useState` hook:
```
import React, { useState } from "react";
```

---

vii. Make `student` state inside the function before the return statement, with an initial value of `null`.
```
const [student, setStudent] = useState(null);
```

---

viii. Save the state & its setter in a variable, we'll call `value`.
```
const value = { student, setStudent };
```

---

ix. Finally, pass this value as props in the `StudentContext.Provider`.
```
<StudentContext.Provider value={ value }>
```

---

### Here's the complete file for `StudentContext.jsx`:<a id="result"></a>
[(back to beginning of example)](#example)

```
// 'StudentContext.jsx'
-----
import React, { useState } from 'react';
const StudentContext = React.createContext();

function StudentProvider({ children }) {
  const [student, setStudent] = useState(null);
  const value = { student, setStudent };
  // console.log('student from StudentContext: ', student)
  return (
    <StudentContext.Provider value={ value }>
      { children }
    </StudentContext.Provider>
  )
}

export { StudentContext, StudentProvider }
```

---

## 2. Wrap Provider around highest level component<a id="wrap"></a>
[(back to top)](#top)

According to [React Docs](https://reactjs.org/docs/context.html#reactcreatecontext), 

> When React renders a component that subscribes to this Context object it will read the current context value from the closest matching Provider above it in the tree.

Remember, the Provider is “providing” access to the Context component (and the state or other variables it may hold) anywhere you need to invoke it.

**Question**: Which components will you need to set or access `student` and `setStudent` in your app? 

Find the top-most parent component they all have in common. This is where we will use our `StudentProvider`.

Since our context is helping us with global state, and for the sake of this example, we're moving all the way up to index.js in the '`/src`' folder. You can place this anywhere that works for your app, just make sure it's "above" anywhere you'll need it in the component hierarchy.

Import `StudentProvider` and wrap it around the root component, which in this case is `<App/>`. 

```
// 'index.js'
-----
import React from 'react';
import ReactDOM from 'react-dom/client';
import { StudentProvider } from './context/StudentContext';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <StudentProvider>
    <App />
  </StudentProvider>
);
```

Now, any child of the `<App />` component is able to import StudentContext if they need to.

---

## 3. Using _useContext()_<a id="using"></a>
[(back to top)](#top)

Now you are able to access and set student state anywhere in your app.

Let's say you are using student data stored on an API. Make a new file under '`/src/components/`' called `Student.jsx`.

i. Start by importing `React`, `useContext` and `StudentContext`.
```
import React, { useContext } from 'react';
import { StudentContext } from '../context/StudentContext';
```

---

ii. Destructure values inside the component function by passing `StudentContext` to the `useContext()` hook.
```
function Student () => {
  const { student, setStudent } = useContext(StudentContext);
  return (<></>)
}
```

From here, you can fetch data from an API and store it with `setStudent` inside a `useEffect` hook, or create a form a user can fill out and save a form data object with `setStudent`. 

Once you set your state with the Context Component you made, you can use that data however you want, passing the `student` variable to this or any other component in your app with the useContext hook. 

You could use it to display a name, provide authorization to view hidden components, or store a schedule, shopping cart, or profile page, to name a few examples. It's really up to you from here what you want to do.

---

## Conclusion<a id="conclusion"></a>
[(back to top)](#top)

Using Context is easy & convenient once you know how it's set up and how it's used. You can keep track of errors, themes, authorization codes, or really anything you might need to keep track of global state.

Keep in mind, anytime you update Context State, the component using that state will re-render. If this isn’t the behavior you want, maybe a [useMemo or useRef](https://reactjs.org/docs/hooks-reference.html) hook might be a better choice. 

Please note: It is advised to use useContext sparingly because of performance issues when your app scales. Only use it if you need it. 

Some React devs think that useContext is bad, for reasons [worth considering](https://blog.thoughtspile.tech/2021/10/04/react-context-dangers/). I like using it for themes & authentication in smaller dynamic apps, like my personal projects.

In the end, it's up to you to decide how to structure your app and make it respond to student interactions how you see fit. This is just one of many ways to keep track of state in a dynamic React application.

I hope this helps, and I wish you well. Happy coding!