How I Set Up Context in React
Tags: react, beginners
Published: 2020-09-29 02:55:52

The Context API is a feature in React that allows your application to have app-level state without the use of a state management library like Redux. It's a neat feature that I highly recommend everyone try out if you're going to be working with React. Setting it up however, can be a bit confusing for beginners. Here, I'm going to outline how I go about setting up Context. This is by no means the "best way" of doing things, so if you have a more efficient way of implementing Context, I'd love to hear it.

First, create a new React app using the `npx create-react-app` command and open up the new project in your code editor. If you did, your file structure should look something like this:
![Screen Shot 2020-09-28 at 5.53.25 PM](https://dev-to-uploads.s3.amazonaws.com/i/yudsd45q7kld3rite2iu.png)

### **Setting Up Context**
**Step 1**: Create a "context" folder in the "src/" directory.
**Step 2**: Create a "type.js" file in the context folder - this will hold your reducer action types.

```react
// src/context/types.js
export const ADD_CONTACT = "ADD_CONTACT"; // this will eventually be passed to the reducer
```
**Step 3**: In the "context" folder, create a folder and name it after the state you will be managing. In this example, I'm making an app that keeps track of a user's contacts, so I named this folder "contact".

**Step 4**: In the "contact" folder, create 3 files for the Context, Reducer, and State. In this example, my files are contactContext, contactReducer, and ContactState:
![Screen Shot 2020-09-28 at 6.13.51 PM](https://dev-to-uploads.s3.amazonaws.com/i/pvun6xc2llavn0su2m1s.png)

**Step 5**: In the contactContext file:
```react
// src/context/contact/contactContext.js
import { createContext } from "react"; 

const contactContext = createContext(); // declare your context variable and set it to a new context using createContext()

export default contactContext;
```
Here we simply initialize a new context and export it. This will be imported into our ContactState.

**Step 6**: In the contactReducer file:
```react
// src/context/contact/contactReducer.js
import {
  ADD_CONTACT
} from "../types"; // import the action types you will be using in this reducer

// export your switch case statement to handle the actions dispatched to the reducer
export default (state, action) => {
  switch (action.type) {
    case ADD_CONTACT:
      return {
        ...state,
        contacts: [...state.contacts, action.payload],
      };
    default:
      return state;
  }
};

```
**Step 7**: In the ContactState file:
```react
// src/context/contact/ContactState.js
import React, { useReducer } from "react"; // import useReducer hook
import { v4 as uuid } from "uuid"; // using uuid to create random ID for a new contact

// import contactContext and contactReducer
import ContactContext from "./contactContext"; 
import ContactReducer from "./contactReducer";

// import types from types.js to be dispatched to ContactReducer vis the useReducer hook
import {
  ADD_CONTACT
} from "../types";

const ContactState = (props) => {
  const initialState = {
    contacts: [
      {
        id: 1,
        name: "John Doe",
        email: "john@gmail.com",
        phone: "111-111-1111",
      }
  };

// pass ContactReducer and initial state to useReducer hook in order to mutate app-level state
  const [state, dispatch] = useReducer(ContactReducer, initialState); 

  // Add Contact
  const addContact = (contact) => {
    contact.id = uuid();
    dispatch({ type: ADD_CONTACT, payload: contact });
  };

  return (
    {/* Return the Context Provider with the value prop set as an object of the state and props we want all components to have access to  */}
    <ContactContext.Provider
      value={{
        contacts: state.contacts, {/* passing down contact state*/}
        addContact {/* passing down a function*/}
      }}
    >
      {props.children}
    </ContactContext.Provider>
  );
};

export default ContactState;
```
**Step 8**: Finally, simply import the `ContactState` into your `App.js` and wrap your entire app in the Provider:
```react
// src/App.js
import React from 'react';
import Contacts from './components/Contacts';
import './App.css';

import ContactState from "./context/contact/ContactState";

const App = () => {
  return (
    {/* Wrap entire app in ContactState, which returns the Provider. This will allow all components in the app to have access to the state in ContactState */}
    <ContactState>
      <Contacts />
    </ContactState>
  );
}

export default App;
```
By wrapping the entire App in ContactState, all the components of App become children of ContactState and can now access the state via the useContext hook.

```react
//src/components/Contacts.js
import React, { useContext } from "react"; // importing useContext hook
import ContactContext from "../../context/contact/contactContext";

const Contacts = () => {
  // declare a context variable with the useContext hook and now the Context component has access to the state from ContactContext
  const contactContext = useContext(ContactContext);

  // destructure out contacts from our contactContext
  const { contacts } = contactContext;

  return (
    <div>
      {contacts.map(contact => <h1>{contact.name}</h1>)}
    </div>
  );
};

export default Contacts;
```