i am using the useNavigate hook inside of react to direct users to a home page after successful login. everything i've read online suggests that i should use the useNavigate hook inside of a useEffect block, but when i do so, it triggers an infinite loop: Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
the odd thing is, though, that the warning only seems to occur after logging in for a second time. what i mean is that it will work on the first login after starting the server & client, but logging in a second, third, etc. time results in a Maximum update depth exceeded
warning.
i use the useNavigate hook in two separate files, a login for users and a login for admin, both of which are below.
for further clarification on the issue arising only on the second login and beyond, it occurs regardless of whether i log in as admin or as a user. for instance, if my first login is as an admin, the Maximum update depth exceeded
warning will occur regardless of whether my next login is as a user or as an admin. the same is true if my first login is as a user.
what i've tried so far:
the error when i login as user:
react-dom.development.js:86 Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
at Navigate (http://localhost:3000/static/js/bundle.js:42950:5)
at Routes (http://localhost:3000/static/js/bundle.js:43067:5)
at div
at Router (http://localhost:3000/static/js/bundle.js:43000:15)
at BrowserRouter (http://localhost:3000/static/js/bundle.js:41809:5)
at App
the error when i login as admin:
react-dom.development.js:86 Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
at Navigate (http://localhost:3000/static/js/bundle.js:42950:5)
at Routes (http://localhost:3000/static/js/bundle.js:43067:5)
at div
at Router (http://localhost:3000/static/js/bundle.js:43000:15)
at BrowserRouter (http://localhost:3000/static/js/bundle.js:41809:5)
at App
Login.jsx
import { useState, useEffect } from "react";
import axios from "axios";
import { Link, useNavigate} from "react-router-dom";
const Login = () => {
const navigate = useNavigate();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
useEffect(() => {
if (localStorage.getItem("authToken")) {
navigate("/home");
}
}, [navigate]);
const loginHandler = async (e) => {
e.preventDefault();
const config = {
header: {
"Content-Type": "application/json",
},
};
try {
const { data } = await axios.post("/api/auth/login", { email, password }, config);
localStorage.setItem("authToken", data.token);
navigate("/home");
} catch (error) {
setError(error.response.data.error);
setTimeout(() => {
setError("");
}, 5000);
}
};
return (
<div className="login-">
<form onSubmit={loginHandler} className="login-__form">
<h3 className="login-__title">Login</h3>
{error && <span className="error-message">{error}</span>}
<div className="form-group">
<label htmlFor="email">Email:</label>
<input
type="email"
required
id="email"
placeholder="Email address"
onChange={(e) => setEmail(e.target.value)}
value={email}
tabIndex={1}
/>
</div>
<div className="form-group">
<label htmlFor="password">
Password:{" "}
{/* <Link to="/forgotpassword" className="login-__forgotpassword">
Forgot Password?
</Link> */}
</label>
<input
type="password"
required
id="password"
autoComplete="true"
placeholder="Enter password"
onChange={(e) => setPassword(e.target.value)}
value={password}
tabIndex={2}
/>
</div>
<button type="submit" className="btn btn-primary">
Login
</button>
<span className="login-__subtext">
Don't have an account? <Link to="/register">Register</Link>
</span>
</form>
</div>
);
};
export default Login;
AdminLogin.jsx
import { useState, useEffect } from "react";
import axios from "axios";
import { Link, useNavigate} from "react-router-dom";
const AdminLogin = () => {
const navigate = useNavigate();
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
useEffect(() => {
if (localStorage.getItem("adminToken")) {
navigate("/admin/home");
}
}, [navigate]);
const adminLoginHandler = async (e) => {
e.preventDefault();
const config = {
header: {
"Content-Type": "application/json",
},
};
try {
const { data } = await axios.post("/api/admin/login", { username, password }, config);
localStorage.setItem("adminToken", data.token);
navigate("/admin/home");
} catch (error) {
setError(error.response.data.error);
setTimeout(() => {
setError("");
}, 5000);
}
};
return (
<div className="login-">
<form onSubmit={adminLoginHandler} className="login-__form">
<h3 className="login-__title">admin login</h3>
{error && <span className="error-message">{error}</span>}
<div className="form-group">
<label htmlFor="username">Username:</label>
<input
type="username"
required
id="username"
placeholder="Username"
onChange={(e) => setUsername(e.target.value)}
value={username}
tabIndex={1}
/>
</div>
<div className="form-group">
<label htmlFor="password">
Password:{" "}
{/* <Link to="/forgotpassword" className="login-__forgotpassword">
Forgot Password?
</Link> */}
</label>
<input
type="password"
required
id="password"
autoComplete="true"
placeholder="Enter password"
onChange={(e) => setPassword(e.target.value)}
value={password}
tabIndex={2}
/>
</div>
<button type="submit" className="btn btn-primary">
Login
</button>
<span className="login-__subtext">
Here by mistake? <Link to="/login">Login</Link>
</span>
</form>
</div>
);
};
export default AdminLogin;
it was asked in a comment, so i've also included Private.jsx (user home page) Admin.jsx (admin home page), though i don't think the issue is in either of these files. Private.jsx
import { useState, useEffect } from "react";
import axios from "axios";
import { useNavigate } from "react-router-dom";
const Private = () => {
const [error, setError] = useState("");
const [privateData, setPrivateData] = useState("");
const navigate = useNavigate();
const handleLogout = () => {
localStorage.removeItem('authToken');
navigate('/login');
console.log('logged out successfully');
}
return error ? (
<span className="error-message">{error}</span>
) : (
<div>
you're in the private route
<button onClick = {handleLogout}>Logout</button>
</div>
);
};
export default Private;
Admin.jsx
import { useNavigate } from 'react-router-dom';
export default function Admin() {
const navigate = useNavigate();
const handleLogout = () => {
localStorage.removeItem('adminToken');
navigate('/admin/login');
console.log('logged out successfully');
}
return (
<>
<div>ADMIN ROUTE UNLOCKED</div>
<button onClick = {handleLogout}>Logout</button>
</>
)
}
You need to listen for changes in your localStorage. Try this:
const checkAuth = () => {
if (localStorage.getItem("authToken")) {
navigate("/home");
}
}
useEffect(() => {
window.addEventListener("storage", checkAuth);
return () => {
window.removeEventListener("storage", checkAuth)
}
}, []);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.