Using React Context to Prevent Prop Drilling
Tags: javascript, react, beginners
Published: 2021-10-04 07:55:26

In this article, I will summarize the usefulness and usage of React Context, which is useful for prop in React.

## Overview
### Problem
If you don’t use React Context and try to pass data to prop, you need to pass the data to prop and receive it again and again. And you won’t know what you are passing if the components are too nested.
For example, as shown in the figure below, when you want to pass the array data ‘languages’ in the green background to container 3, you can implement it in two patterns: with using React Context and without using React Context.


#### Pattern 1 (with using React Context)
![with using React Context](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rily5bfzbd1jrnfc2g0s.png)


#### Pattern 2 (without using React Context)
![without using React Context](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q0uurshy3f5mpsjvef5f.png)


In the case of Pattern 2, where the React Context is not used, the data is passed in the following order: Background → Container1 → Container2 → Container3. Even though the data is only used in Container3, Prop is being passed again and again, called **prop drilling**.

The code for this looks like the following.
```javascript
import "./App.css";

function App() {
  const languages = ["JavaScript", "Python", "Java", "Golang"];
  return (
    <div className="background">
      Background　
      <p className="languages">
        Pass languages[JavaScript, Python, Java, Golang] to Container 3
      </p>
      {/* languages ->  Container1*/}
      <Container1 languages={languages} />
    </div>
  );
}

export default App;

function Container1({ languages }) {
  return (
    <div className="container1">
      Container 1
      <Container2 languages={languages} />
      {/* Container1 ->  Container2 */}
    </div>
  );
}

function Container2({ languages }) {
  return (
    <div className="container2">
      Container 2
      <Container3 languages={languages} />
      {/* Container2 ->  Container3 */}
    </div>
  );
}

function Container3({ languages }) {
  return (
    <div className="container3">
      Container 3
      <ul className="languages-area">
        {languages.map((language, i) => (
          <li key={i}>{language}</li>
        ))}
      </ul>
    </div>
  );
}
```


Container1 and Container2 receive data and carry the data to Container3, even though they do not actually use the data.
This is not impossible to do, but if there are 10 layers of components, it will no longer be clear what data is being passed or received.


### Solution
So you will use React Context to pass data directly from Background to Component3. It’s easy to use, and here’s an image of React Context.
![React Context Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h97950gkvalncnedxe6z.png)

Create a friend Mr. B who is a mutual friend of Mr. A and Mr. C, and pass and receive data through Mr. B.


## Implementation
### Step 1. import React Context
First, import the react context.
Then, use createContext() to declare a context called LanguageContext.
↑ The one created here is the so-called common friend Mr. B of Mr. A and Mr. C. He will receive and pass data.

```javascript
import "./App.css";
import { createContext, useContext } from "react";

const LanguageContext = createContext();
```

### Step 2. Pass the data to Context
Using the Provider, pass the data you want to pass to the LanguageContext you just created.
This is like passing the data to your mutual friend B.


#### Note
・The range that can receive the data passed to LanguageContext is only the range enclosed by LanguageContext.
・The value to be written in LanguageContext.Provider must be ‘value’.

```javascript
import "./App.css";
import { createContext, useContext } from "react";

const LanguageContext = createContext();

//  Added code below
function App() {
  const languages = ["JavaScript", "Python", "Java", "Golang"];
  return (
    <LanguageContext.Provider value={{ languages }}>
      <div className="background">
        Background　
        <p className="languages">
          Pass languages[JavaScript, Python, Java, Golang] to Container 3
        </p>
        <Container1 />
      </div>
    </LanguageContext.Provider>
```

### Step 3. Writing parts that are not related to data transfer
The code is cleaner than the code without React Context because there is no need to receive or pass prop.

```javascript
import "./App.css";
import { createContext, useContext } from "react";

const LanguageContext = createContext();

function App() {
  const languages = ["JavaScript", "Python", "Java", "Golang"];
  return (
    <LanguageContext.Provider value={{ languages }}>
      <div className="background">
        Background　
        <p className="languages">
          Pass languages[JavaScript, Python, Java, Golang] to Container 3
        </p>
        <Container1 />
      </div>
    </LanguageContext.Provider>
  );
}

// Added code below
function Container1() {
  return (
    <div className="container1">
      Container 1
      <Container2 />
    </div>
  );
}

function Container2() {
  return (
    <div className="container2">
      Container 2
      <Container3 />
    </div>
  );
```

### Step 4. Receive data from Context
In the part of the component that you want to receive data (Container3 in this case), use useContext() to receive the data.
For arguments in useContext(), put context = LanguageContext. And it will be useContext(LanguageContext). Then, you can receive the data passed by the Provider.

```javascript
import "./App.css";
import { createContext, useContext } from "react";

const LanguageContext = createContext();

function App() {
  const languages = ["JavaScript", "Python", "Java", "Golang"];
  return (
    <LanguageContext.Provider value={{ languages }}>
      <div className="background">
        Background　
        <p className="languages">
          Pass languages[JavaScript, Python, Java, Golang] to Container 3
        </p>
        <Container1 />
      </div>
    </LanguageContext.Provider>
  );
}

function Container1() {
  return (
    <div className="container1">
      Container 1
      <Container2 />
    </div>
  );
}

function Container2() {
  return (
    <div className="container2">
      Container 2
      <Container3 />
    </div>
  );
  
// Added code below
function Container3() {
  const ctx = useContext(LanguageContext);
  console.log(ctx.languages);
  return <p>{ctx.languages}</p>;
}
```
Then, you are able to receive the data as you expect.
`["JavaScript", "Python", "Java", "Golang"];`

### Step5. Use the received data
Then, you just use the data as always. And this is the completed code.
```javascript
import "./App.css";
import { createContext, useContext } from "react";

const LanguageContext = createContext();

function App() {
  const languages = ["JavaScript", "Python", "Java", "Golang"];
  return (
    <LanguageContext.Provider value={{ languages }}>
      <div className="background">
        Background　
        <p className="languages">
          Pass languages[JavaScript, Python, Java, Golang] to Container 3
        </p>
        <Container1 />
      </div>
    </LanguageContext.Provider>
  );
}

function Container1() {
  return (
    <div className="container1">
      Container 1
      <Container2 />
    </div>
  );
}

function Container2() {
  return (
    <div className="container2">
      Container 2
      <Container3 />
    </div>
  );
  
// Added code below
function Container3() {
  const ctx = useContext(LanguageContext);
  console.log(ctx.languages);
  return (
    <div className="container3">
      Container 3
      <ul className="languages-area">
        {ctx.languages.map((language, i) => (
          <li key={i}>{language}</li>
        ))}
      </ul>
    </div>
  );
}
```

#### Note
Normally, you would create a folder called “store” and create the LanguageContext.js in it. And create a context and export it, but in this case, for ease of viewing, I’ve included everything in the same file.


## Summary
These are the steps to use React Context:
Step1. import React Context, and create React Context
Step2. Pass the data to Context
Step3. Write components whatever you want
Step4. Receive data from Context
Step5. Use the received data

The code I wrote in this post including css is in [Github](https://github.com/Sho-ki/my-react-context)