Typeerror: Cannot Read Property 'pathname' of Undefined React Router
Login App – Create login form in ReactJS using secure REST API – Part 3
Today we'll show you how to create login grade in ReactJS using secure Rest API with example. It's the terminal office of the login application where we will create the login course in ReactJS and integrate the Node.js secure Remainder API.
Before you keep, we want you to cheque out the starting time & second parts of this article. You can also check the following video for React Login App.
Way to create login form in ReactJS using secure Balance API
- Create secure REST API
- Setup react application
- Create react components like Dwelling house, Login and Dashboard
- Implement authenticated routes
- Output
one. Create secure Residual API
To create login application, nosotros need secure REST API to integrate into the application. And so nosotros have already created the REST API in Node.js for authentication. Kindly refer the beneath article to create it or clone information technology from the GitHub repository.
Login App – Create REST API for authentication in Node.js using JWT – Part 2
Afterward that just run the project and so we can consume the REST API.
2. Setup react application
First, Permit's setup the simple react application to implement the login functionality. Following link will help you to create basic react application.
Create React Application
3. Create react components similar Domicile, Login and Dashboard
Now, It's fourth dimension to create components for Home, Login and Dashboard pages and link it using the routing.
- Home component (Admission it with/without login) – It's a simple component which we can admission information technology with/without user login. By default we'll open this component.
- Login component (Access it without login only) – Hither nosotros will create a login page. Then with the help of it nosotros tin can call the Residuum API and on successful telephone call nosotros will redirect it on the Dashboard component.
- Dashboard component (Access it afterward login only) – Information technology's a private folio that users tin can admission but after successfully logged in. Nosotros will also provide the option to logout from user business relationship in the same component.
If you don't know how to implement routing in react app and then refer to the post-obit link for routing.
Routing in React JS
For demo purpose we are creating these components and updating the css in "src" directory.
Home.js
| import React from 'react' ; function Home ( ) { return ( < div > Welcome to the Home Folio ! </div > ) ; } export default Dwelling ; |
Login.js
| 1 ii 3 four 5 6 7 viii 9 10 eleven 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 xxx 31 32 33 34 35 36 37 38 39 40 41 42 43 | import React , { useState } from 'react' ; function Login ( props ) { const username = useFormInput ( '' ) ; const password = useFormInput ( '' ) ; const [ error , setError ] = useState ( null ) ; const [ loading , setLoading ] = useState ( simulated ) ; // handle push click of login form const handleLogin = ( ) => { props . history . push ( '/dashboard' ) ; } return ( < div > Login < br /> < br /> < div > Username < br /> < input blazon="text" { . . . username } autoComplete="new-countersign" /> </div > < div style={ { marginTop : 10 } } > Countersign < br /> < input type="password" { . . . password } autoComplete="new-password" /> </div > { error && <><minor style={{ color: 'red' }}>{error}</small><br /></>}<br /> <input type="button" value={loading ? 'Loading...' : 'Login'} onClick={handleLogin} disabled={loading} /><br /> </div> ); } const useFormInput = initialValue => { const [ value , setValue ] = useState ( initialValue ) ; const handleChange = e => { setValue ( e . target . value ) ; } return { value , onChange : handleChange } } export default Login ; |
Dashboard.js
| one 2 3 4 5 six 7 eight ix ten 11 12 thirteen 14 15 16 17 18 | import React from 'react' ; office Dashboard ( props ) { // handle click event of logout push const handleLogout = ( ) => { props . history . push ( '/login' ) ; } return ( < div > Welcome User ! < br /> < br /> < input type="push" onClick={ handleLogout } value="Logout" /> </div > ) ; } export default Dashboard ; |
App.js
| 1 ii 3 4 5 6 7 8 9 10 xi 12 13 14 15 16 17 18 nineteen xx 21 22 23 24 25 26 27 28 29 30 31 | import React from 'react' ; import { BrowserRouter , Switch , Route , NavLink } from 'react-router-dom' ; import Login from './Login' ; import Dashboard from './Dashboard' ; import Abode from './Home' ; function App ( ) { return ( < div className="App" > < BrowserRouter > < div > < div className="header" > < NavLink verbal activeClassName="active" to="/" > Home </NavLink > < NavLink activeClassName="agile" to="/login" > Login </NavLink > < small > ( Access without token only ) </small > < NavLink activeClassName="active" to="/dashboard" > Dashboard </NavLink > < small > ( Admission with token only ) </small > </div > < div className="content" > < Switch > < Route exact path="/" component={ Home } /> < Route path="/login" component={ Login } /> < Route path="/dashboard" component={ Dashboard } /> </Switch > </div > </div > </BrowserRouter > </div > ) ; } export default App ; |
index.js
| import React from 'react' ; import ReactDOM from 'react-dom' ; import './alphabetize.css' ; import App from './App' ; ReactDOM . render ( < App /> , document . getElementById ( 'root' ) ) ; |
alphabetize.css
| 1 ii iii four five 6 7 viii 9 10 11 12 13 fourteen 15 16 17 xviii 19 twenty 21 22 23 24 25 26 27 28 29 xxx 31 32 33 34 35 36 37 38 | body { margin : 0 ; font-family : -apple-arrangement , BlinkMacSystemFont , "Segoe UI" , "Roboto" , "Oxygen" , "Ubuntu" , "Cantarell" , "Fira Sans" , "Droid Sans" , "Helvetica Neue" , sans-serif ; -webkit-font-smoothing : antialiased ; -moz-osx-font-smoothing : grayscale ; } lawmaking { font-family : source-code-pro , Menlo , Monaco , Consolas , "Courier New" , monospace ; } . content { padding : 20px ; } . header { padding : 10px ; background : #edf2f4; border-lesser : 1px solid #999; } . header a { color : #0072ff; text-decoration : none ; margin-left : 20px ; margin-right : 5px ; } . header a : hover { color : #8a0f53; } . header minor { color : #666; } . header . active { color : #2c7613; } |
4. Implement authenticated routes
Permit's integrate the secure API to the react application. Follow the beneath steps to do it.
- Create common utils
- Integrate sign in API
- Manage the logout in dashboard
- Create public and individual routes
- Handle the browser refresh
-
Create common utils
To manage the login and logout functionality, we need to create a few functions in "Common.js" file which will help us to manage token and user data using
sessionStorage. Here we volition create this file in "src/Utils" directory.src/Utils/Common.js
1
two
3
4
5
6
7
8
ix
10
xi
12
xiii
xiv
xv
16
17
xviii
19
xx
21
22
23
// return the user data from the session storage
export const getUser = ( ) => {
const userStr = sessionStorage . getItem ( 'user' ) ;
if ( userStr ) render JSON . parse ( userStr ) ;
else render null ;
}
// return the token from the session storage
export const getToken = ( ) => {
return sessionStorage . getItem ( 'token' ) | | zilch ;
}
// remove the token and user from the session storage
export const removeUserSession = ( ) => {
sessionStorage . removeItem ( 'token' ) ;
sessionStorage . removeItem ( 'user' ) ;
}
// fix the token and user from the session storage
export const setUserSession = ( token , user ) => {
sessionStorage . setItem ( 'token' , token ) ;
sessionStorage . setItem ( 'user' , JSON . stringify ( user ) ) ;
}
-
Integrate sign in API
Allow's integrate the "/users/signin" API on the click event of the login push button. Refer to the below link if you don't know how to call API in ReactJS.
API call in React JSHither, we used the axios for the API call. Afterward successful login, we are storing the response information in sessionStorage and redirect it to the dashboard page. Also managing the loading and mistake flag via
useState.src/Login.js
one
2
3
4
5
half dozen
7
viii
9
10
11
12
13
14
15
xvi
17
18
19
20
21
22
23
24
25
26
27
28
29
xxx
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import React , { useState } from 'react' ;
import axios from 'axios' ;
import { setUserSession } from './Utils/Common' ;
function Login ( props ) {
const [ loading , setLoading ] = useState ( false ) ;
const username = useFormInput ( '' ) ;
const password = useFormInput ( '' ) ;
const [ error , setError ] = useState ( naught ) ;
// handle button click of login form
const handleLogin = ( ) => {
setError ( nix ) ;
setLoading ( true ) ;
axios . mail ( 'http://localhost:4000/users/signin' , { username : username . value , password : password . value } ) . and then ( response => {
setLoading ( false ) ;
setUserSession ( response . information . token , response . information . user ) ;
props . history . push ( '/dashboard' ) ;
} ) . take hold of ( error => {
setLoading ( false ) ;
if ( error . response . status === 401 ) setError ( fault . response . data . message ) ;
else setError ( "Something went wrong. Please try again later." ) ;
} ) ;
}
return (
< div >
Login < br /> < br />
< div >
Username < br />
< input type="text" { . . . username } autoComplete="new-password" />
</div >
< div style={ { marginTop : 10 } } >
Password < br />
< input type="password" { . . . countersign } autoComplete="new-countersign" />
</div >
{ fault && <><small mode={{ color: 'red' }}>{error}</pocket-sized><br /></>}<br />
<input type="button" value={loading ? 'Loading...' : 'Login'} onClick={handleLogin} disabled={loading} /><br />
</div>
);
}
const useFormInput = initialValue => {
const [ value , setValue ] = useState ( initialValue ) ;
const handleChange = eastward => {
setValue ( e . target . value ) ;
}
return {
value ,
onChange : handleChange
}
}
export default Login ;
-
Manage the logout in dashboard
On click of the Logout push button, we are removing the information from the sessionStorage and redirect it to the login page. Also we are showing the user name on page of the Dashboard.
src/Dashboard.js
one
2
three
4
5
6
7
eight
nine
10
11
12
13
14
xv
16
17
xviii
xix
twenty
21
import React from 'react' ;
import { getUser , removeUserSession } from './Utils/Mutual' ;
function Dashboard ( props ) {
const user = getUser ( ) ;
// handle click effect of logout push
const handleLogout = ( ) => {
removeUserSession ( ) ;
props . history . push ( '/login' ) ;
}
return (
< div >
Welcome { user . name } ! < br /> < br />
< input blazon="push button" onClick={ handleLogout } value="Logout" />
</div >
) ;
}
consign default Dashboard ;
-
Create public and individual routes
We divided routes in iii parts.
- Normal routes – Which we can apply to access routes with or without user login.
- Public routes – Which we can use to access the routes without login token only. So if user is already logged-in then we will redirect it to the dashboard folio.
- Private routes – Which we tin can use to access the routes with login token only. So if user is not logged-in then we will redirect back it to the login page.
Utils/PrivateRoute.js
import React from 'react' ;
import { Route , Redirect } from 'react-router-dom' ;
import { getToken } from './Common' ;
// handle the private routes
office PrivateRoute ( { component : Component , . . . rest } ) {
return (
< Route
{ . . . rest }
return={ ( props ) => getToken ( ) ? < Component { . . . props } /> : < Redirect to={ { pathname : '/login' , land : { from : props . location } } } /> }
/>
)
}
export default PrivateRoute ;
Utils/PublicRoute.js
import React from 'react' ;
import { Route , Redirect } from 'react-router-dom' ;
import { getToken } from './Common' ;
// handle the public routes
function PublicRoute ( { component : Component , . . . residuum } ) {
render (
< Route
{ . . . remainder }
render={ ( props ) => ! getToken ( ) ? < Component { . . . props } /> : < Redirect to={ { pathname : '/dashboard' } } /> }
/>
)
}
export default PublicRoute ;
Now we take to slightly update the routes in "App.js" to implement hallmark.
. . .
. . .
import PrivateRoute from './Utils/PrivateRoute' ;
import PublicRoute from './Utils/PublicRoute' ;
. . .
. . .
< Switch >
< Route exact path="/" component={ Home } />
< PublicRoute path="/login" component={ Login } />
< PrivateRoute path="/dashboard" component={ Dashboard } />
</Switch >
. . .
. . .
export default App ;
-
Handle the browser refresh
At last, we have to handle the browser refresh to authenticate the awarding. For that we will integrate 1 more than API called "/verifyToken" and manage the hallmark flag. Based on the authentication flag we volition manage the loading screen.
App.js
ane
ii
3
4
5
six
7
8
nine
10
xi
12
13
14
15
16
17
xviii
19
20
21
22
23
24
25
26
27
28
29
thirty
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import React , { useState , useEffect } from 'react' ;
import { BrowserRouter , Switch , Route , NavLink } from 'react-router-dom' ;
import axios from 'axios' ;
import Login from './Login' ;
import Dashboard from './Dashboard' ;
import Home from './Home' ;
import PrivateRoute from './Utils/PrivateRoute' ;
import PublicRoute from './Utils/PublicRoute' ;
import { getToken , removeUserSession , setUserSession } from './Utils/Common' ;
role App ( ) {
const [ authLoading , setAuthLoading ] = useState ( truthful ) ;
useEffect ( ( ) => {
const token = getToken ( ) ;
if ( ! token ) {
return ;
}
axios . get ( ` http : //localhost:4000/verifyToken?token=${token}`).and then(response => {
setUserSession ( response . information . token , response . data . user ) ;
setAuthLoading ( false ) ;
} ) . grab ( fault => {
removeUserSession ( ) ;
setAuthLoading ( false ) ;
} ) ;
} , [ ] ) ;
if ( authLoading && getToken()) {
return <div className="content">Checking Authentication...</div>
}
return (
<div className="App">
<BrowserRouter>
<div>
<div className="header">
<NavLink exact activeClassName="active" to="/">Dwelling house</NavLink>
<NavLink activeClassName="active" to="/login">Login</NavLink><small>(Access without token just)</pocket-sized>
<NavLink activeClassName="agile" to="/dashboard">Dashboard</NavLink><small>(Access with token just)</pocket-size>
</div>
<div className="content">
<Switch>
<Road verbal path="/" component={Home} />
<PublicRoute path="/login" component={Login} />
<PrivateRoute path="/dashboard" component={Dashboard} />
</Switch>
</div>
</div>
</BrowserRouter>
</div>
);
}
export default App ;
5. Output
Run the login awarding and check information technology in the browser.
In this article, we accept covered the general straight forward menstruum of the hallmark. Cheque out the beneath commodity where you will find the more secure manner to implement hallmark including refresh token and CSRF protection.
Login App with CSRF protection
Demo & Source Code
Github Repository StackBlitz Projection
If you constitute value in this article,
you can support us past buying me a coffee! ☕
Y'all may too like...
Source: https://www.cluemediator.com/login-app-create-login-form-in-reactjs-using-secure-rest-api
0 Response to "Typeerror: Cannot Read Property 'pathname' of Undefined React Router"
Post a Comment