Context in React Hooks
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
When React version 16.3 came out it had an interesting feature, Context. Now, why was it introduced? To understand it let’s take up an example.
The Project
From Fig1 we can see that Component1 has many sub-components namely, Component2, Component 3, Component 4, and a Button.
When I click the button, the border-color of Component1 goes from red to black, the border-color of Component4 goes from black to red, and the button whose text was black on white alternates to white on black.
This change in color is achieved using state. My state is initially false and then at the press of the button, I alternate its value.
We can see that the button click affects only Component1, Component4, and Button. Component2 and Component3 remain unaffected by it.
Component 1
This component holds the state dark
and the function changeToDark
using which we can alternate its value. Initially dark
is false so the border-color is red in Component1 as you can see in Fig 2.
Component1 passes the state and the function as props to Component2.
Component2 and Component3
These two components have no functionality other than passing the props from the parent component to the child component. Component2 receives props from Component1 and passes it down to Component3. Component3 receives props from its parent Component2 and passes it down to Component4.
Component4
This component receives the props but only uses the dark
property to change its border-color. When dark
is initially false border-color is black and when we press the button the border-color changes to red as its value changes to true.
Button
This component uses the value of dark
to change its background-color and color property, and on clicking the button it calls the function changeToDark
to alter the value of dark
and simultaneously cause changes in the UI.
The Problem
As you can see from above that at every level we have to pass down the state dark
and the function changeToDark
associated with it. Now, this is a small project so it doesn’t matter that much to pass them down as props.
But the question is…
What if my project had like 30 sub-components in it?
What if there were multiple states and functionalities that I had to pass down to the sub-components?
Then it would become quite confusing to tackle so many props. And I had to pass it down through components that may have no use of it, like Component2 and Component3 in my case.
This problem is known as Prop Drilling.
Prop drilling (also called “threading”) refers to the process you have to go through to get data to parts of the React Component tree.
In this project, dark
and changeToDark
are the data and they have to reach the bottom-most level of my React Component Tree.
The Solution
The ContextAPI was introduced to overcome this problem regarding prop drilling.
For this, we need to create a context object using React.createContext()
The value false
is the default value of the context.
Component1
In fig 8, I have imported MyContext in Component1 to use it. Now every Context comes with a Provider React component. As its name suggests it “provides” values to its sub-components. In this case MyContext.Provider
has a value
which is a property containing the state dark
and the function changeToDark
as an object. The sub-components when they try and access the value, they use the value which is provided by the nearest context Provider, in this case, which is Component1. We can also see that earlier, we had to pass the data down to Component2 as props but, now we don’t do it.
Component2 and Component3
Earlier Component2 and Component3 had no use of the props dark
and changeToDark
but still, we had to pass it down since the components, which are below them in the component tree, require it. But now we have don’t have to do it.
When we use Context we don’t have to pass down the data as props. Hence Prop Drilling which was a major disadvantage had been avoided.
Component4
React Hooks provided a function useContext
, this function allowed us to access the value which is provided by the nearest context provider. In this case, the nearest context provider is Component1 hence the values that are provided by it are used. Since value
is an object we can access the state using value.dark
and the function using value.changeToDark
.
As the current context value is determined with dark
which is my state, whenever it is changed it causes a re-render in all the functions which use it.
Button
Similarly, in this case too the function useContext
is used to access the value of the nearest context provider and its values are used accordingly.
The functionality of Button has remained the same, except we have used Context now.
Conclusion
Throughout the entire process, the logic of the code has not changed. Instead, we used a new feature to overcome the problem of prop drilling that we were dealing with earlier.
Similar to Context, there is Redux which deals with the same problem regarding props. Context basically provides us a way to pass down data at different component levels without using props and this is the reason why Context Matters.