已登录用户禁止访问登录页面问题:登录页闪显后跳转
解决已登录用户访问登录页闪显问题
问题核心是初始认证状态设为false,组件先渲染登录界面,异步请求完成后才更新状态跳转,导致页面短暂闪显。以下是具体解决方案:
1. 优化初始认证状态判断
利用登录成功后存入的localStorage直接初始化认证状态,减少等待异步请求的时间:
const [isAuthenticated, setIsAuthenticated] = useState(() => { // 从localStorage读取初始认证状态 return localStorage.getItem("authenticated") === "true"; });
2. 添加加载状态,避免提前渲染登录界面
新增isLoading状态,在异步请求完成前不渲染登录界面:
const [isLoading, setIsLoading] = useState(true); // 初始为加载中
在useEffect的请求回调里,无论认证结果如何,都标记加载完成:
useEffect(() => { fetch("http://localhost:8000/session/", { credentials: "include" }) .then((res) => res.json()) .then((data) => { if (data.isAuthenticated) { setIsAuthenticated(true); localStorage.setItem("authenticated", true); // 同步localStorage状态 } else { setIsAuthenticated(false); localStorage.removeItem("authenticated"); // 同步localStorage状态 getCsrf(); } setIsLoading(false); // 请求完成,结束加载 }) .catch((err) => { console.log(err); setIsLoading(false); // 出错也结束加载 }); }, []);
3. 调整组件返回逻辑
加载状态时返回占位容器(保持布局一致,避免页面跳动),认证通过则跳转,否则渲染登录界面:
// 加载中返回占位 if (isLoading) { return <div className="login-box m-auto"></div>; } if(isAuthenticated) { return <Navigate replace to="/admin/dashboard" />; } else { return loginScreen; }
完整修改后的组件代码
import { useEffect, useState } from "react" import { Navigate } from "react-router-dom"; import { useNavigate } from "react-router-dom"; function AdminLogin() { const navigate = useNavigate() // 从localStorage初始化认证状态 const [isAuthenticated, setIsAuthenticated] = useState(() => { return localStorage.getItem("authenticated") === "true"; }); const [isLoading, setIsLoading] = useState(true); // 新增加载状态 const [csrf, setCsrf] = useState('') const [username, setUsername] = useState('') const [password, setPassword] = useState('') function getCsrf(){ fetch("http://localhost:8000/csrf/", { credentials: "include" }) .then((res) => { let csrfToken = res.headers.get("X-CSRFToken"); setCsrf({csrf: csrfToken}); }) .catch((err) => { console.log(err); }) } const login = (event) => { event.preventDefault(); fetch("http://localhost:8000/login/", { method: "POST", headers: { "Content-Type": "application/json", "X-CSRFToken": csrf.csrf, }, credentials: "include", body: JSON.stringify({username: username, password: password}), }) .then(isResponseOk) .then((data) => { console.log(data); setIsAuthenticated(true) localStorage.setItem("authenticated", true); setUsername('') setPassword('') }) .catch((err) => { console.log('inside login catch') console.log(csrf.csrf, 'catch') console.log(err); }); } const isResponseOk = (response) =>{ if (response.status >= 200 && response.status <= 299) { return response.json(); } else { console.log(response) throw Error(response.statusText); } } useEffect(() => { fetch("http://localhost:8000/session/", { credentials: "include" }) .then((res) => res.json()) .then((data) => { if (data.isAuthenticated) { setIsAuthenticated(true); localStorage.setItem("authenticated", true); } else { setIsAuthenticated(false); localStorage.removeItem("authenticated"); getCsrf(); } setIsLoading(false); // 结束加载 }) .catch((err) => { console.log(err); setIsLoading(false); // 出错也结束加载 }); }, []) const handleUsername = (e) => { setUsername(e.target.value) } const handlePassword = (e) => { setPassword(e.target.value) } const loginScreen = ( <div className="login-box m-auto"> <div className="card"> <div className="card-body login-card-body"> <p className="login-box-msg">Sign in to start your session</p> <form method="post" onSubmit={login}> <div className="input-group mb-3"> <input required type="text" value={username} onChange={handleUsername} className="form-control" placeholder="Username" /> <div className="input-group-append"> <div className="input-group-text"> <span className="fas fa-envelope" /> </div> </div> </div> <div className="input-group mb-3"> <input required type="password" value={password} onChange={handlePassword} className="form-control" placeholder="Password" /> <div className="input-group-append"> <div className="input-group-text"> <span className="fas fa-lock" /> </div> </div> </div> <div className="row"> <div className="col-4"> <button type="submit" className="btn btn-primary btn-block">Sign In</button> </div> </div> </form> </div> </div> </div>) // 加载中返回占位 if (isLoading) { return <div className="login-box m-auto"></div>; } if(isAuthenticated) { return <Navigate replace to="/admin/dashboard" />; } else { return loginScreen; } }
内容的提问来源于stack exchange,提问作者sash
相关产品推荐
相关产品推荐

