React状态不立即更新致登录需双击跳转,求技术解决方案
问题原因分析
你遇到的两次点击才跳转的问题,核心是React的状态更新是异步批量处理的:在handleAuth中调用setIsLogged(true)和setCurrentUser后,组件不会立刻更新状态,此时立刻调用navigateAfterLogin,函数内读取的还是更新前的isLogged(false)和currentUser(初始空对象),所以第一次点击无法触发跳转;第二次点击时状态已完成更新,才能正确执行导航逻辑。
不需要用useRef替代state,只需调整导航逻辑即可解决问题。
解决方案
推荐直接使用loginCheck返回的用户数据进行导航,无需等待state异步更新,逻辑更简洁可靠:
修改后的完整代码
import { Route, Routes, Link} from "react-router-dom"; import Home from "./pages/Home"; import Login from "./pages/Login"; import Profile from "./pages/Profile"; import { useNavigate } from "react-router-dom"; import { useState} from 'react'; function App() { const [currentUser, setCurrentUser] = useState({id:null, username:null, password:null}); const [userInput, setUserInput] = useState(""); const [passInput, setPassInput] = useState(""); const [isLogged, setIsLogged] = useState(false); const navigate = useNavigate(); const data = [ { id: 1, username: "jane", password: "1234",isAdmin:true }, { id: 2, username: "jack", password: "1234", isAdmin: false }, { id: 3, username: "john", password: "1234" , isAdmin:false}, { id: 4, username: "elizabeth", password: "1234", isAdmin: false} ]; const loginCheck = (username, password) => { console.log("logincheck function working"); const getUserData = data.find(user => user.username === username && user.password === password); console.log(getUserData); if(getUserData){ console.log(`${getUserData.username} logged in`); return getUserData; } else { console.log("user not found"); return null; } }; const handleAuth = () => { console.log("handlesubmit function working"); const gelen = loginCheck(userInput, passInput); if (gelen) { // 更新状态 setIsLogged(true); setCurrentUser(gelen); // 直接用校验返回的用户数据导航 navigateAfterLogin(gelen); } else { setIsLogged(false); setCurrentUser({id:null, username:null, password:null}); navigateAfterLogin(null); } } // 导航函数接收用户数据参数,不再依赖组件state const navigateAfterLogin = (user) => { console.log("navigation function working."); if (user) { console.log("redirecting to profile page"); const timer = setTimeout(() => { navigate(`/users/${user.username}`, { state: { id: user.id, username: user.username, isAdmin: user.isAdmin } }); }, 3000); return () => clearTimeout(timer); } else { console.log("redirecting to login page"); navigate(`/login`); } }; return ( <div> <h1>Navbar</h1> <Link to="/">Home</Link> <Link to="login">Login</Link> <input name="username" type="text" placeholder="username" onChange={(e)=> setUserInput(e.target.value)} /> <input name="password" type="password" placeholder="password" onChange={(e)=> setPassInput(e.target.value)}/> <button onClick={handleAuth} type="submit">Login</button> <div style={{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center"}}> <h1> <label>hesabınıza giriş yapın</label> </h1> </div> <Routes> <Route path="/" element={<Home />} /> <Route path="login" element={<Login />} /> <Route path="users/:id" element={<Profile/>} /> <Route path="*" element={<h1>404 not found</h1>} /> </Routes> </div> ); } export default App;
备选方案:通过useEffect监听状态导航
如果一定要依赖state变化触发导航,可以使用useEffect监听状态更新,此时需要移除handleAuth中对navigateAfterLogin的调用:
import { useEffect } from 'react'; // ... 其他代码保持不变 useEffect(() => { if (isLogged && currentUser.id) { const timer = setTimeout(() => { navigate(`/users/${currentUser.username}`, { state: { id: currentUser.id, username: currentUser.username, isAdmin: currentUser.isAdmin } }); }, 3000); return () => clearTimeout(timer); } else if (!isLogged && !currentUser.id) { navigate('/login'); } }, [isLogged, currentUser, navigate]);
内容的提问来源于stack exchange,提问作者berk
相关产品推荐
相关产品推荐

