React Context and Hooks: An excellent way to pass data
What is Context?
A Context is basically a JavaScript object that can be passed from one parent component to several child components efficiently. Props can pass values to components as well. But, if a value needs to be passed to a child component deep in the component tree, using props means the value also passes through components that do not need it. Or, if a value is required by several components, props can make it difficult.
This is a good use case for Context. Props need to be passed from one component to the other. With Context, the parent component provides the value, and the child components that need it can access it.
Passing values with Context and Hooks
Let's take a common example used for demonstrating Context - themes. Consider the following UI:
Here, the one with the red border is the main App.js
component. The one with the green border is a component called ThemeButton.js
, and the one with a blue border is the ThemeWindow.js
component. The App
component will have the other two as its child components. Clicking the button in ThemeButton
will toggle the theme between light and dark. The result of the theme will be reflected in ThemeWindow
.
We need to create a context first, then have the App
component provide a value for its child components. The child component(s) will consume this provided value. Let's set this up.
1. Creating a context
A context can be created in a separate file or in the App
component itself, but it is generally better to create a separate file for it. Since depending on your app, you may need multiple contexts for different features. It can thus be useful to have separate files.
Create a new file to hold the context and export it:
In this file, we export two things - an object containing theme values and our context. The createContext()
function returns a Context object. It accepts an argument for the initial value similar to the useState
hook. In this case, the light themes object is the default value of ThemeContext
.
2. Passing values with the Provider component
Since the context has been created, let's add it in App.js
.
Every Context object (created with React.createContext()
) has a Provider component. This Provider component should be wrapped around all the child components that will be getting access to ThemeContext
. Conversely, there is also a Consumer component. You can also use the useContext
hook instead if you're not working with class-based components.
You must be wondering why the light object was used as the default value, but the Provider component has passed the dark object. First of all, the value
prop used in the Provider component is something React recognizes so you cannot use a different name for that prop.
Whatever is passed through the value
prop is what the child components consume. And if a component attempts to access ThemeContext
but does not have a Provider component in the tree above, it will use the default value the Context object has (the light theme).
As a quick example, let's say there was a third component called ThemeFont.js
. But this third component was not included within the Provider component -
Since ThemeFont
is not wrapped by the Provider component, it will not receive the new value. Although it can still access ThemeContext
, it will receive the default value, that is, the value we passed to createContext
- the light themes object.
Not wrapping a component that needs access to a Context in a Provider component still gives it access to the Context's default value.
Although you probably wouldn't have a reason to do this, it is still good to know.
3. Consuming context in child components
Let's use React Hooks to consume the provided context value.
Running this app, you would get the following result:
The ThemeWindow
certainly has the dark theme. But, the button to toggle the theme doesn't work. The next article will demonstrate how to update values passed via Context.