React Context API - Why, How and When ? With full example.
Tags: react, redux, javascript, frontend
Published: 2021-08-16 10:11:00

Hello everybody, in this article we are gonna go deeper and deeper in some React more complex topics like state management, let's get going ... 
<br/> 
One of the most important features about React is that we have a lot of different ways to solve any problem we face. And one of this problems we might have is 'State Management' issues in React. 
<br/>
First, let's say we building an e-commerce app, so we want to display a list of products and we want to have a navigation bar in a head, so let's make a component with the products list first `ProductList.js`.
<br/>
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/78zvkgj7o1frdpsdkvxx.png)
So I'm just created a new React component with **ProductList.js** name.
<br/>
Now, we need a `state` Hook to store our products list array on objects form, I just want tow properties in each product object, it's `productName` and `productIamge`. <br/>
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q7ypw9ofp3f7mwh37vek.png) <br/>
So now, I just want to render this products as a cards using some `CSS` and `products.map()` method so you can imagen this cards listed in a screen like so. 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8n803zq9zkvp9ugf2vxq.png)
<br/>
We know that one of the concepts of React is you can split your app into components for reusability purposes and to be more maintainable code. So we want to make another component called **Product.js** that receives product image and name as a **prop** and return this products one by one to be rendered :  
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/khs4e5wlmpabrxhv9hf8.png) <br/>
and calls this component inside `products.map()` method in `ProductList.js` like so : 
![Render products one by one from ProductList.js coponent](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kifya5cx696ijtnqrry0.png) <br/>

Now, I want create a navbar in a top of our app that contain my name and the number of products I have in my list, so I will create `Nav.js` component and render it in our `App.js` component with some `css` ..
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f7r6qw8kglzf3w9ncqf6.png) </br>
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j8odfoapxhh9hj73dzoy.png)
Ok, everything is fine ..
Now I want to render the number of products I have in the `ProductList.js` to `Nav.js` component **and I can't do that !!** <br/> Because I have rendered the `Nav` component in the `App.js` that not have an access to our state in `ProductLis.js` component and the only way to do that is to passing the state `length` down to **props** ..
The only way is we will render the `Nav.js` component in our `ProductList.js` component like so :
![Rendering Nav.js in ProductList.js](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e7wjgveukrje795w2t90.png)
But I don't want to render the `Nav.js` here ! it's make no sense to have the navbar in my `ProductList.js` so we will fix this in take the `state` from `ProductList.js`, cut it, and move it up to `App.js` (the parent component) like so :
 
![Move the state to App.js parent component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/je7f1vhkst91xiqmcmtu.png)
In this way, now we can pass down the products to our navbar and products list, so we can pass it to any component we want.

**But, the problem with that** we will have a lot of state in our `App.js` component that doesn't belong to `App.js` component, so this will work, but will be a bit difficult, **Why?**

Because if we also want to pass down props we're gonna have **Prop Drill**.

**What is Prop Drilling ?**</br>
It's basically means we will **pass props down from component to components to components to components until we arrives the component we want..**
So we would have keep passing the props over and over and over again..!<br/>
So in our example, we will passing the `products` state :
1- from `App.js` to `ProductList.js` component
2- from `ProductList.js` to `Product.js` component
3- from `App.js` to `Nav.js` component
4- and more and more ..<br/>
It's a big problem that's effects the app performance and make it hard to read, understand and to be edited.

So we will go back and pass everything back up so the way we were in the first place.
![Back to our first stage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ykt2p6fzz8e68ubbtf9.png)
<br/>
So The way to fix the "Prop drilling issue" is with **State Management**.

React offers a way to manage our state which is called **context**. The way this works is rather than adding the state in particular component, we can separate that logic into one component called `Context Component` that's holds all information, then with the context we can pass it down to which every component we want without going to props.<br/>

So let's take a look how we can do that, I will create a new file and I gonna call this `ProductsContext.js`.
Inside this file I gonna `import React from 'react'`
and make a new component `ProductsProvider` as ES6 function component and `export` it but not default because I want export tow different things from this component like so : (I will explain everything don't worry)
![make a products provider component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9hgqqv629wfo8rpctk9m.png)
Now, what we want to do ? 

*First step :*
I will move our `products state` from `ProductList.js` component to `ProductsProvider` component and import `useState` in it like this :
![Moving our state](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9bex2vsgsrj7p9ygxytm.png)<br/>
*Second step :*
Now, we want create our **context**, the first step to create any React **context** is with `createContext` function from react:

#createContext#
To start with the Context API, the first thing we need to do is create a context using the createContext function after we import it from React like so :
`import {createContext} from 'react' ;`.
The second thing is to create our context like so: 
`export const ProductsContext = createContext(initialValue);`<br/>
** The createContext function accepts an initial value, but this initial value is ***not*** required.<br/>
![createContext](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/udod5xuo2wabvvg7zoey.png)<br/>
After creating the context, our context now has ***tow*** React components to be used: *Provider* and *Consumer*.<br/>
**Provider :**
The Provider component is going to be used to wrap the components that are going to have access to our context, such as `Product.js` and `Nav.js` who are the `children` of `App.js` component in our example.
So, we will import our `productsProvider` in `App.js` component first, then we will use it to wrap other components we want to give an access to the context like so :
![Wrap components inside our context](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fs7zwgbkrb0tgx6qk0a9.png)
So now everything in the `productsProvider` are easily accessible for `Product.js` and `Nav.js`. <br/>
Now, we will go back to our ContextProvider component and make some changes in our `ProductsProvider` function.
In this function we will make it receives a prop that holds **consumers** children and return the `ProductsContext.Provider` component like so :

` <ProductsContext.Provider value={products}>
     {prop.children}
  </ProductsContext.Provider>
`

The Provider component receives a prop called value, which can be accessed from all the components that are wrapped inside Provider, and it will be responsible to grant access to the context data.
The component will be like this after this changes :</br>

![add context.provider component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/thnipndyl4us6gkuthmc.png)
**`{prop.children}` represents the components wrapped inside the `ProductsProvider` component in `App.js`.<br/>

**So, how we can use our context now ?**
*Third step :*
#useContext#<br/>
React has a built-in hooks such as `useState`, `useCallback`, `useEffect`, etc. But the one that we’re going to talk and learn more about here is the `useContext` hook.<br/>
The `useContext` hook allows us to connect and **consume** a context. The `useContext` hook receives a single argument, which is the context that you want to have access to.<br/>
So, first we must import our context which is already defined from previous steps in the component we want to **consume** this context :
`import {ProductsContext} from './ProductsContext';`
and then we must import `useContext` from react :
`import {useContext} from 'react';`

*I will use the context in `ProductList.js` first*
So, I will say 
`const products = useContext(ProductsContext);` like so :
![Using useContext](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m4fbi25yu5l2pbs00c8h.png)
Now, if we `console.log(products)` will get an array of objects that contains this products data and we can use it as we like and everywhere without using props !!
**Congratulations** 😍✌

Now, we can use this data and display products in our app, display the number of products we have in `Nav.js` component very fast like so.

*ProductList.js :*
![display products](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5z1rszzwyzmezpbph5u9.png)<br/>
*Nav.js :*
![display number of items](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/owq4fwkyammo01ui5wpf.png)<br/>
#Conclusion
In this article, we learned more about the React Context API. The Context API came to solve problems that we were having in React applications. One of the most important is *prop-drilling* issue. We created a simple example using the React Context API. Also, we were learned how to use the `useContext` hook.

I hope you will forgive me if there are any mistakes.
Don't forget to support me 🙌🌹
Best wishes ❤