To be honest I avoided using Context for a long time. I easily began to use hooks, but I did not immediately understand Сontext. In this article I will show you one way to use Context.
const App = () => { <Switch> <Route path=”/profile” component={ProfilePage} /> <Route path=”/login” component={LoginPage} /> <Redirect to=”/login” /> </Switch> };
Let's restrict access to the ProfilePage
- only authenticated users can access this page. If the user is a guest, we redirect him to the login page.
const LoginPage = () => { const [redirectTo, setRedirectTo] = useState(null); const submitHandler = e => { e.preventDefault(); const formData = new FormData(e.target); authenticate(formData).then(user => { if (user.authenticated) { this.setState({ redirectTo: ‘/profile’ }); } }); } if (redirectTo) { return ( <Redirect to={redirectTo} /> ); } return ( <Form omSubmit={submitHandler}> <Form.Input required type=”email” name=”email” label=”Email” /> <Form.Input required type=”password” name=”password” label=”Password” /> <Form.Button type=”submit” /> </Form> ); };
The authenticate
method sends user credentials to the API. When we get a response, we redirect the user to the ProfilePage
. All is well, except for one trifle - everyone can access to the ProfilePage
without authentication. To fix this, we need a flag - a global variable - to indicate whether the user is authenticated or not. Let's create Context that allows us to send a flag to components.
import React, { useState } from ‘react’; export const AuthContext = React.createContext(); export const AuthProvider = ({ children }) => { const [authenticated, setAuthenticated] = useState(false); return ( <AuthContext.Provider value={{authenticated, setAuthenticated}}> {children} </AuthContext.Provider> ); }; export const AuthConsumer = AuthContext.Consumer;
Go to the App.js
file and wrap the Switch
into the AuthProvider
. AuthContext.Provider
allows us to pass the context value - the authenticated
flag and the setAuthenticated
method - to all child components.
import { AuthProvider } from ‘./authContext’; const App = () => { <AuthProvider> <Switch> <Route path=”/profile” component={ProfilePage} /> <Route path=”/login” component={LoginPage} /> <Redirect to=”/login” /> </Switch> <AuthProvider> };
And make changes to the LoginPage
.
import React, { useState, useContext } from ‘react’; import { AuthContext } from ‘./authContext’; const LoginPage = () => { const context = useContext(AuthContext); const [redirectTo, setRedirectTo] = useState(null); const submitHandler = e => { e.preventDefault(); const formData = new FormData(e.target); authenticate(formData).then(user => { context.setAuthenticated(true);
Now we just have to subscribe to the changes and send off a guest.
import { AuthConsumer } from ‘./authContext’; const ProtectedRoute = ({ component: Component, ...rest }) => ( <Route {...rest} render={matchProps => ( <AuthConsumer> {value => ( <Fragment> {value.authenticated || ( <Redirect to=”/login” /> )} <Component {...matchProps} /> </Fragment> )} </AuthConsumer> )} /> );
Consumer is a React component, that subscribes to Context changes. It takes the function as a child and passes the current Context value to it.
Finishing touch.
import { AuthProvider } from ‘./authContext’; import { ProtectedRoute } from’./ProtectedRoute’; const App = () => { <AuthProvider> <Switch> <ProtectedRoute path=”/profile” component={ProfilePage} /> <Route path=”/login” component={LoginPage} /> <Redirect to=”/login” /> </Switch> <AuthProvider> };
Top comments (0)