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:
class A extends React.Component {
state = {
value: 'Some value'
};
render() {
return(
);
}
}
const B = (props) => (
);
const C = (props) => (
{props.value}
);
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.).
// AuthUser.jsx
import React, { Component } from 'react';
import { authenticateUser } from './Auth';
// initialize Context with default value
export const AuthCtx = React.createContext(null);
const AuthenticateUser = (ComposedComponent) => {
class Authenticate extends Component {
state = {
userAuth: null
};
async componentDidMount() {
try {
// make API request to authenticate user on the backend
const { status, data } = await authenticateUser();
if (status === 200) {
this.setState({ userAuth: data });
}
} catch (err) {
// handle error
}
}
render() {
const { userAuth } = this.state;
return(
);
}
}
return Authenticate;
};
export 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:
// NavBar.jsx
import React from 'react';
import { Link } from 'react-router-dom';
import AuthenticateUser, { AuthCtx } from './AuthUser';
const NavBar = () => (
{userAuth =>
!userAuth ? (
Login
) : (
Profile
Logout
...
)
}
);
export 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 <AuthCtx.Consumer>
component, just like we did for the NavBar.
Der Beitrag Using the New Context API with Higher Order Components in React erschien zuerst auf codecentric AG Blog.