I am implementing security and user management in my application and ran into an issue with react router, Context, localStorage.
With router, I have created a private route and I check if the userID exists on Context or localStorage, if userID does not exist then I re-direct the user to the sign in page. This works great, BUT if I refresh the page, it ALWAYS redirects to the sign in page. Even though the user is logged in, and should exist on localStorage.
I think the issue stems from localStorage and "useEffect()". My theory is that the router redirects BEFORE localStorage (and useEffect) is done checking if the userID exists. Not sure how I can go around this?
Here's the code for my Private Route component"
import {
Route,
Redirect,
RouteProps,
} from 'react-router-dom';
import {MyContextProvider, useMyContext} from '../Context/UserContext';
interface PrivateRouteProps extends RouteProps {
// tslint:disable-next-line:no-any
component: any;
UserID: number;
}
const PrivateRoute = (props: PrivateRouteProps) => {
const { component: Component, UserID, ...rest } = props;
console.log("Inside Route: "+ UserID);
return (
<Route
{...rest}
render={(routeProps) =>
UserID > 0 ? (
<Component {...routeProps} />
) : (
<Redirect
to={{
pathname: '/',
state: { from: routeProps.location }
}}
/>
)
}
/>
);
};
export default PrivateRoute;
^ The " console.log("Inside Route: "+ UserID); " prints a 0, so thats why it always redirects to sign in page. This is why I think the useEffect() (shown below in routing) may have something to do with userID not being set properly.
Code for Routing part:
function Routing() {
const classes = useStyles();
const [store, setStore] = useMyContext();
useEffect(() => { // check if user exists in localstorage, if so, set the values on react Context
const res = localStorage.getItem("UserID");
if (res) {
// since LocalStorage can return a type or null, we must check for nulls and set accordingly.
const uID = localStorage.getItem("UserID");
const UserID = uID !== null ? parseInt(uID) : 0;
const un = localStorage.getItem("Username");
const Username = un !== null ? un : '';
const iA = localStorage.getItem("IsAdmin");
const isAdmin = iA != 'true' ? true : false;
const eN = localStorage.getItem("EmailNotifications");
const emailNotifications = eN != 'true' ? true : false;
setStore({ // update the 'global' context with the logged in user data
UserID:UserID,
Username: Username,
IsAdmin: isAdmin,
EmailNotifications: emailNotifications
});
console.log(UserID);
console.log(Username);
console.log(isAdmin);
console.log("foundUser");
}
}, []);
const id = store.UserID; // get the userID from context; to pass into PrivateRoute
console.log("ID: ++"+ id);
return (
<div className="App">
<Router>
<Switch>
<Route exact path="/" component={Login}/>
<PrivateRoute path="/dashboard" UserID={id} component={Dashboard}/>
<PrivateRoute path="/add" UserID={id} component={AddTicket}/>
<PrivateRoute path="/settings" UserID={id} component={Settings}/>
<Route component={NotFound}/>
</Switch>
</Router>
</div>
);
}
export default Routing;