DEV Community

Cover image for React Context API - Why, How and When ? With full example.
Ahmad Mukahal
Ahmad Mukahal

Posted on

React Context API - Why, How and When ? With full example.

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 ...


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.


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.


Alt Text
So I'm just created a new React component with ProductList.js name.


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.

Alt Text

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


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

and calls this component inside products.map() method in ProductList.js like so :
Render products one by one from ProductList.js coponent

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
Alt Text
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 !!
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
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
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 ?
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..!

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 ..

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


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.

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
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

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);

** The createContext function accepts an initial value, but this initial value is not required.

createContext

After creating the context, our context now has tow React components to be used: Provider and Consumer.

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
So now everything in the productsProvider are easily accessible for Product.js and Nav.js.

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 :

add context.provider component
**{prop.children} represents the components wrapped inside the ProductsProvider component in App.js.

So, how we can use our context now ?
Third step :

useContext#

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.

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.

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
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

Nav.js :
display number of items

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 ❀

Discussion (0)