DEV Community

Victor Magarlamov
Victor Magarlamov

Posted on

Authentication in React App with Context

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)