I've implement a simple protected route
from Login
& other protected components
.
universal-cookie
to persist user data/tokenContext API
Login.js
redirect
to Dashboard.js
(home page for logged-in users)ProtectedRouteLogin.js
:-import React, { useEffect } from 'react'
import { Redirect, Route } from 'react-router-dom'
import { useAuth } from '../../../contexts/Auth/AuthState'
import { isAuthenticated, setLoading } from '../../../contexts/Auth/AuthAction'
const ProtectedRoute\Login = ({ component: Component, ...rest }) => {
const [authState, authDispatch] = useAuth()
const { authenticated, loading } = authState
// check if user is authenticated
useEffect(() => {
(async() => {
await isAuthenticated(authDispatch)
setLoading(authDispatch, false)
})();
}, [])
return (
<Route
{...rest} render={
props => {
if(loading) return <div className="lds-hourglass"></div>
if(!authenticated) return <Component {...props} />
else return <Redirect exact to={{
// here I redirect logged-in user to dashboard
pathname: "/dashboard",
state: { from: props.location }
}} />
}
}
/>
)
}
export default ProtectedRouteLogin
Dashboard.js
or other protected componentscomponent
. Otherwise, redirect
to Login
pageProtectedRouteOthers.js
:-import React, { useEffect } from 'react'
import { Redirect, Route } from 'react-router-dom'
import { useAuth } from '../../../contexts/Auth/AuthState'
import { isAuthenticated, setLoading } from '../../../contexts/Auth/AuthAction'
const ProtectedRouteOthers = ({ component: Component, ...rest }) => {
const [authState, authDispatch] = useAuth()
const { authenticated, loading } = authState
// check if user is authenticated
useEffect(() => {
(async() => {
await isAuthenticated(authDispatch)
setLoading(authDispatch, false)
})();
}, [])
return (
<Route
{...rest} render={
props => {
if(loading) return <div className="lds-hourglass"></div>
if(authenticated) return <Component {...props} />
else return <Redirect to={
{
// here redirect NOT logged-in user back to login page
pathname: "/login",
state: { from: props.location }
}
} />
}
}
/>
)
}
export default ProtectedRouteOthers
Since the checking (user aunthentication) is done in protected route layer or component
just before rendering
any protected routes, I'm having an issue where whenever I refreshed page (when logged-in). It keeps bring me back to Dashboard.js
page.
I reckoned, this have something todo with having my authenticated
state
in Context API
is false
by default
. Every time, I hit refreshed, the authenticated
state
will be false
first in default
state
until I change/update it, after checking user cookie exist or not. (this is done in isAunthenticated
function in Context API
which was called in both Protected Routed above)
isAuthenticated
function (check if user have cookie or not)
export const isAuthenticated = async(dispatch) => {
setLoading(dispatch, true)
// get user cookie
let userExist = getCookie('user')
/** Cookie Checking Style */
if(userExist) {
dispatch({
type: 'SET_ISAUTHENTICATED',
payload: true
})
} else {
dispatch({
type: 'SET_ISAUTHENTICATED',
payload: false
})
}
}
So how can I alter my code so that, every time i refresh my protected page (when logged-in). I will stay on the refreshed page, instead of going back to the Dashboard
page?
Luckily I found a solution. But I don't know whether this is an acceptable solution or not. At least this logic make sense to overcome my issue.
I decided to add a logic before rendering Login.js
page & other protected components
in both Protected Route components
(logic added in ProtectedRouteLogin.js
& ProtectedRouteOthers
)
ProtectedRouteLogin.js
Dashboard.js
page, if user is authenticated, I check for props.location.pathname
saved in cookie
first. If present/exist, then render
to said pathname
. Otherwise, just render
to Dashboard.js
pageProtectedRouteLogin.js
:-import React, { useEffect } from 'react'
import { Redirect, Route } from 'react-router-dom'
import { useAuth } from '../../../contexts/Auth/AuthState'
import { isAuthenticated, setLoading } from '../../../contexts/Auth/AuthAction'
import { getCookie } from '../../../services/Cookie'
const ProtectedRouteLogin = ({ component: Component, ...rest }) => {
const [authState, authDispatch] = useAuth()
const { authenticated, loading } = authState
// check if user is authenticated
useEffect(() => {
(async() => {
await isAuthenticated(authDispatch)
setLoading(authDispatch, false)
})();
}, [])
return (
<Route
{...rest} render={
props => {
if(loading) return <div className="lds-hourglass"></div>
if(!authenticated) return <Component {...props} />
else {
// get pathname save in cookie
let url = getCookie('onRefresh')
return <Redirect exact to={{
// ternary function to determine redirection
pathname: url !== '' ? url : '/pfv4-admin/dashboard',
state: { from: props.location }
}} />
}
}
}
/>
)
}
export default ProtectedRouteLogin
ProtectedRouteOthers.js
components
, I set cookie
that gonna hold the props.location.pathname
or url of about-to visit component
. So that, I can cross-check this url in ProtectedRouteLogin.js
above.ProtectedRouteOthers.js
:-import React, { useEffect } from 'react'
import { Redirect, Route } from 'react-router-dom'
import { useAuth } from '../../../contexts/Auth/AuthState'
import { isAuthenticated, setLoading } from '../../../contexts/Auth/AuthAction'
import { setCookie } from '../../../services/Cookie'
const ProtectedRouteOthers = ({ component: Component, ...rest }) => {
const [authState, authDispatch] = useAuth()
const { authenticated, loading } = authState
// check if user is authenticated
useEffect(() => {
(async() => {
await isAuthenticated(authDispatch)
setLoading(authDispatch, false)
})();
}, [])
return (
<Route
{...rest} render={
props => {
if(loading) return <div className="lds-hourglass"></div>
if(authenticated) {
// save last page seen address (url)
setCookie('onRefresh', props.location.pathname, { path: '/' })
return <Component {...props} />
}
else return <Redirect to={
{
pathname: "/pfv4-admin",
state: { from: props.location }
}
} />
}
}
/>
)
}
export default ProtectedRouteOthers
Feel free to add your own possible solution for this issue tho. Looking forward to try them.