'React Routing unable to route properly
I am trying to create a route for admin pages. Codes can be found below. My current issue is that my currentUser has my authenticated user obj and userType is False, but I still can access /createUser page.
AdminRoute.js
import React from 'react'
import { Route, Redirect } from 'react-router-dom'
import { useAuth } from '../../contexts/AuthContext'
const AdminRoute = (props) => {
const { currentUser } = useAuth();
const userType = localStorage.getItem('admin');
if (currentUser === undefined) {
return null;
}
console.log(userType)
return currentUser && userType
? (
<Route {...props} />
)
: (
<Redirect to={{
pathname: "/homepage",
state: {
from: props.location
}
}} />
)
}
export default AdminRoute
Route.js
<Router>
<Switch>
<AdminRoute path='/createUser' component={Register} />
</Switch>
</Router>
Step 1: Login.js
async function handleSubmit(e) {
e.preventDefault()
try {
setError('')
setLoading(true)
await login(emailRef.current.value, passwordRef.current.value)
history.push('/homepage')
} catch {
console.log("heh")
}
setLoading(false)
}
Step 2: HandleSubmit will call function from AuthContext.js.
This is the AuthContext.js where I get the currentUser after authenticating at firebase
import React, { useContext, useState, useEffect } from "react"
import { auth, database } from "../firebase";
import { getDocs, query, where } from "firebase/firestore";
const AuthContext = React.createContext()
export function useAuth() {
return useContext(AuthContext)
}
export function AuthProvider({ children }) {
const [currentUser, setCurrentUser] = useState(null)
const [loading, setLoading] = useState(true)
function login(email, password) {
return auth.signInWithEmailAndPassword(email, password).then(() => {
const Doc = query(database.usersRef, where("email", "==", email));
getDocs(Doc).then((querySnapshot) => {
let values = '';
querySnapshot.forEach((doc) => {
values = doc.id;
// Setting user type in session storage
if (doc.data().userType === "Administrator") {
localStorage.setItem('admin', false);
} else {
localStorage.setItem('admin', false);
}
});
var userUpdate = database.usersRef.doc(values);
userUpdate.update({
lastActive: new Date().toLocaleString('en-SG'),
})
})
});
}
function logout() {
return auth.signOut();
}
function forgetPassword(email) {
return auth.sendPasswordResetEmail(email);
}
function updateEmail(email) {
return currentUser.updateEmail(email)
}
function updatePassword(password) {
return currentUser.updatePassword(password)
}
function updateDisplayName(name) {
return currentUser.updateDisplayName(name)
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged( user => {
setLoading(false)
setCurrentUser(user)
})
return unsubscribe
}, [])
const value = {
currentUser,
login,
forgetPassword,
logout,
updateEmail,
updatePassword,
updateDisplayName,
}
return (
<AuthContext.Provider value={value}>
{!loading && children}
</AuthContext.Provider>
)
}
Solution 1:[1]
I think I see the issue. The code is not JSON serializing/deserializing the "admin" state it is persisting and loading from localStorage.
In your console run:
localStorage.setItem('admin', false)
const userType = localStorage.getItem('admin')
typeof userType
userType
localStorage.getItem('admin'); returns a JSON string, "false", and when you console log it you don't see the quotes. "false" is a truthy value, so the currentUser && userType boolean expression evaluates true when a user is authenticated and there was a value stored in localStorage under the "admin" key.
You should always JSON serialize/deserialize to/from localStorage.
const AdminRoute = (props) => {
const { currentUser } = useAuth();
const userType = JSON.parse(localStorage.getItem('admin') ?? false);
if (currentUser === undefined) {
return null;
}
return currentUser && userType
? (
<Route {...props} />
)
: (
<Redirect to={{
pathname: "/homepage",
state: {
from: props.location
}
}} />
);
}
login
...
// Setting user type in session storage
localStorage.setItem('admin', JSON.stringify(doc.data().userType === "Administrator"));
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Drew Reese |

