What is the new Context API and what problem does it solve?
React Context API is a feature used for sharing the global state and passing it all the way down through the components tree. This can be useful when we need to pass some props from the parent component A
, down to the child component C
which is a child of component B
.
Let’s consider this hypothetical code example:
1class A extends React.Component {
2 state = {
3 value: 'Some value'
4 };
5
6 render() {
7 return(
8 <B value={this.state.value} />
9 );
10 }
11}
12
13const B = (props) => (
14 <C value={props.value} />
15);
16
17const C = (props) => (
18 <div>{props.value}</div>
19);
In this example, we are sending value
from the parent component A
through its child component B
, to be used only inside the child component C
. Component B
doesn’t care about the value
prop, and it’s only passing down that prop to be used in component C
.
This is something commonly known as Prop Drilling – passing props down from an upper level to a lower level in the components tree, while components in between don’t care about these props.
When to use Context?
As React’s official documentation suggests, you shouldn’t use Context just to avoid passing props a few levels down, but rather when you need to share the same data in many different components at multiple levels (e.g. theming, localization, authentication, etc.).
1// AuthUser.jsx
2import React, { Component } from 'react';
3import { authenticateUser } from './Auth';
4
5// initialize Context with default value
6export const AuthCtx = React.createContext(null);
7
8const AuthenticateUser = (ComposedComponent) => {
9 class Authenticate extends Component {
10 state = {
11 userAuth: null
12 };
13
14 async componentDidMount() {
15 try {
16 // make API request to authenticate user on the backend
17 const { status, data } = await authenticateUser();
18 if (status === 200) {
19 this.setState({ userAuth: data });
20 }
21 } catch (err) {
22 // handle error
23 }
24 }
25
26 render() {
27 const { userAuth } = this.state;
28 return(
29 <AuthCtx.Provider value={userAuth}>
30 <ComposedComponent />
31 </AuthCtx.Provider>
32 );
33 }
34 }
35 return Authenticate;
36};
37
38export default AuthenticateUser;
We’ve first created Context using the createContext()
method, which returns Provider
and Consumer
objects. We are passing userAuth
to the Provider
’s prop, value
making it available to all of its children, so that AuthCtx
’s Consumer
instance below in the hierarchy tree can access (consume) it.
We’ve implemented AuthenticateUser
reusable Higher Order Component to abstract business logic. This HOC returns ComposedComponent
passed as an argument that we’ve just wrapped into Context
’s Provider
component.
Next, we are going to use this Higher Order Component to enhance and wrap our NavBar
component:
1// NavBar.jsx
2import React from 'react';
3import { Link } from 'react-router-dom';
4import AuthenticateUser, { AuthCtx } from './AuthUser';
5
6const NavBar = () => (
7 <div className="nav-bar">
8 <AuthCtx.Consumer>
9 {userAuth =>
10 !userAuth ? (
11 <Link to="/login">Login</Link>
12 ) : (
13 <Link to="/profile">Profile</Link>
14 <Link to="/logout">Logout</Link>
15 ...
16 )
17 }
18 </AuthCtx.Consumer>
19 </div>
20);
21
22export default AuthenticateUser(NavBar);
Consumer
subscribes to the context’s changes, and it uses the render props pattern to consume provided userAuth
context.
Conclusion
Whenever we need to display some data only if a user is logged in, we can now simply wrap that component with the AuthenticateUser
higher-order component to provide the context, and check if user is authenticated inside the component, just like we did for the NavBar.
More articles
fromBojan Aleksic
Your job at codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
More articles in this subject area
Discover exciting further topics and let the codecentric world inspire you.
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Blog author
Bojan Aleksic
Do you still have questions? Just send me a message.
Do you still have questions? Just send me a message.