On login click I am hitting the login api to login and setting the response in states in redux toolkit.
This is the login button listener:
export const SigninApi = (toast, nav) => async (dispatch) => {
try {
const username = document.getElementsByName("username")[0].value;
const password = document.getElementsByName("password")[0].value;
if (!username) {
dispatch(setUsernameError("Username is required"));
return;
} else {
dispatch(setUsernameError(""));
}
if (!password) {
dispatch(setPasswordError("Password is required"));
return;
} else {
dispatch(setPasswordError(""));
}
const formdata = {
username: username,
password: password,
domain: window.location.origin,
};
dispatch(setLoading(true));
let response = await axios.post(`${baseurl}/login`, formdata);
console.log;
if (Object.keys(response.data.data.user).length !== 0) {
const token = JSON.stringify(response?.data?.data?.user?.token);
localStorage.setItem("token", token);
dispatch(setToken(token));
const jsonData = JSON.stringify(response.data?.data?.user);
localStorage.setItem("user", jsonData);
dispatch(setUser(response?.data?.data?.user));
toast({
title: "Success",
description: "Signin Successfully.",
status: "success",
isClosable: true,
position: "top-right",
});
nav.push("/admin");
} else {
dispatch(setUser(null));
dispatch(setToken(null));
console.log("error", response?.data?.message);
toast({
title: "Singin Error",
description: response?.data?.message,
status: "error",
duration: 3000,
isClosable: true,
position: "top-right",
});
}
} catch (error) {
dispatch(setUser(null));
dispatch(setToken(null));
console.log("error", error);
toast({
title: "SingIn Error",
description: error?.response?.data?.message,
status: "error",
duration: 3000,
isClosable: true,
});
}
};
After setting states when I navigate to '/admin'
or '/'
or '/admin/dashboard'
or any route I get this error:
Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
If I don't route and just do window.location.reload()
, there is no error
I am using useHistory()
hook of react-router-dom
(I know I am using old version of react-router-dom
which supports useHistory
)
passing nav as an argument which is
const nav = useHistory();
and same error when I navigate after logout. I dont know what is the problem because I am navigating everywhere in other components and there is no issue at all
This is Index.js where I am handling parent routes
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Switch, Redirect } from "react-router-dom";
import AuthLayout from "layouts/Auth.jsx";
import AdminLayout from "layouts/Admin.jsx";
import { Provider } from "react-redux";
import store from "./redux/store";
import { ColorModeScript } from "@chakra-ui/system";
import theme from "theme/theme";
import PageNotFound from "views/404/PageNotFound";
import "./index.css";
const isAuthenticated = localStorage.getItem("token")
? JSON.parse(localStorage.getItem("token"))
: null;
// HOC for authenticated routes
const ProtectedRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={(props) =>
!isAuthenticated ? (
<Redirect to="/auth/signin" />
) : (
<Component {...props} />
)
}
/>
);
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<ColorModeScript initialColorMode={theme.config.initialColorMode} />
<Switch>
<Route path="/auth" component={AuthLayout} />
<Route path="/404" component={PageNotFound} />
<ProtectedRoute path="/admin" component={AdminLayout} />
<Redirect
exact
from="/"
to={!isAuthenticated ? "/auth/signin" : "/admin/dashboard"}
/>
</Switch>
</BrowserRouter>
</Provider>,
document.getElementById("root")
);
The isAuthenticated
value isn't checked as a condition of entering the route. It is computed once when the code loads and never changes.
Update ProtectedRoute
to check localStorage when accessing the route. Move the isAuthenticated
computation into the component.
Example:
const ProtectedRoute = ({ component: Component, ...rest }) => {
const isAuthenticated = localStorage.getItem("token")
? JSON.parse(localStorage.getItem("token"))
: null;
return (
<Route
{...rest}
render={(props) =>
!isAuthenticated ? (
<Redirect to="/auth/signin" />
) : (
<Component {...props} />
)
}
/>
);
};
Also, a more conventional way to implement ProtectedRoute
is as follows:
const ProtectedRoute = (props) => {
const isAuthenticated = localStorage.getItem("token")
? JSON.parse(localStorage.getItem("token"))
: null;
return !isAuthenticated
? (
<Redirect to="/auth/signin" />
) : (
<Route {...props} />
);
};