I am working on my personal React project. The React app has a login page. After successfully logging in, the user is redirected to homepage i.e. on path / . And if the user again tries to navigate to login page i.e. path /login , then the user will be redirected back to homepage
The app also has protected route on path /profile which is accessible only if the user is authenticated.
But the problem is, when the user navigates to protected route and then refreshes the page, it is redirecting to the homepage. How can I make it redirect back to the same protected route from where the user had refreshed?
Here is Login.js
// Login.js
if (isUserLoggedIn) {
return <Redirect to="/" />;
}
// else render login page
And here is ProtectedRoute.js
import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { Redirect, Route } from "react-router";
export default function ProtectedRoute({ component: Component, ...rest }) {
const { isUserLoggedIn } = useSelector((state) => state.common);
return (
<Route
{...rest}
render={(props) =>
!isUserLoggedIn ? <Redirect to="/login" /> : <Component {...props} />
}
/>
);
}
And this is how I'm getting the value of isUserLoggedIn from cookies and then setting it to the Redux state.
const [authenticated] = useState(() =>
Boolean(Number(Cookies.get("isUserLoggedIn")))
);
useEffect(() => {
if (!authenticated) {
return dispatch({
type: NOT_AUTHENTICATED,
});
} else {
return dispatch({
type: AUTHENTICATED,
});
}
}, [authenticated]);
CodePudding user response:
In simpler terms, you will have to make the browser remember that the user is now authenticated. That can be simply achieved by adding a specific token
or isValid = true
to the session storage and then you will have to use the value from session storage as your reference.
Updating user status in the state cannot persist it on reload. You would have to use persistor
then. However, the easier way is to update session storage.
You can create a new JS file, say session.js
and create the following functions:
export const setToken = (value) => {
sessionStorage.setItem('token', value)
}
export const getToken = () => {
return sessionStorage.getItem('token') || null
}
export const removeToken = () => {
sessionStorage.removeItem('token')
}
You can call setToken(true)
on successful authentication and remove the token removeToken()
on log out. You can then call getToken()
to check your user's authentication in your if
statement. I hope it helps!
CodePudding user response:
It happened same with me. I have solved this problem by using a variable that will be in Local storage so when siging in also set localstorage variable isLogged to true localStorage.setItem("isLogged", true)
so in case he is already logged and refreshed the page the user will redirected to profile page.
The switch statement is used bacause we get string value from localstorage and we have to convert it to boolean
function App() {
const token = localStorage.getItem("isLogged");
let auth = null;
switch (token) {
case "true":
auth = true;
break;
case "false":
auth = false;
break;
default:
break;
}}
as the code above you can now pass the variable auth to the component in protected route like this
<PrivateRoute
path="/main"
component={Main}
isAuthenticated={auth}
></PrivateRoute>
and in the Private Route Component add the isAuthenticated props
const PrivateRoute = ({ component: Component, isAuthenticated, ...props }) => {
return (
<Route
{...props}
render={(props) =>
isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login",
}}
/>
)
}
/>
);
};
This is the Login Component
const Login = () => {
const history = useHistory();
async function onSubmit(data) {
try {
await signin(data.userName, data.password);
localStorage.setItem("isLogged", true);
toast.success("Registerd successfully");
history.go("/main");
} catch {
toast.error("Error");
}
}
return (
<div className="form-container">
<img src={Logo} alt="logo" className="logo-img"></img>
<h1>Login to Your Account</h1>
<Form onSubmit={onSubmit} className="form-items">
{({ handleSubmit }) => (
<form onSubmit={handleSubmit}>
<Field name="userName">
{({ input }) => (
<TextField
name="userName"
type="input"
id="standard-basic"
label="user Name"
variant="standard"
fullWidth
{...input}
/>
)}
</Field>
<Field name="password">
{({ input }) => (
<TextField
name="password"
type="password"
id="standard-basic"
label="Password"
variant="standard"
fullWidth
{...input}
/>
)}
</Field>
<Button
type="submit"
sx={{
width: "100%",
backgroundColor: "rgba(56, 211, 159, 255)",
marginTop: "40px",
color: "white",
}}
>
Login
</Button>
<div>
Don't Have an Account <Link to="/register">Sign up</Link>
</div>
</form>
)}
</Form>
</div>
);
};