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
.
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
.
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.
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 :
and calls this component inside products.map()
method in ProductList.js
like so :
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
..
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 :
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 :
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.
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)
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 :
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.
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 :
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 :
**{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 :
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.
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 β€
Top comments (0)