You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Router V6中useNavigate登录后跳转失效问题求助

登录后跳转异常问题

登录成功后调用navigate("/modules"),目标页面仅在URL中短暂显示,随即被PublicRoute组件重定向至/welcome页面。推测原因是登录前处于PublicRoutes下的登录页,登录成功后该路由变为禁止访问状态,触发了PublicRoutes的默认重定向,覆盖了登录流程中指定的跳转目标。


相关代码

应用入口与路由结构

main.jsx

ReactDOM.createRoot(document.getElementById('root')).render(
<BrowserRouter>
  <AuthContextProvider>
    <App />
  </AuthContextProvider>
</BrowserRouter>
)

App.jsx

function App() {
  return (
    <Routes>
      <Route path='/' element={<SharedLayout/>}>
        <Route element={<PrivateRoutes/>}>
          <Route path="/welcome" element={<PrivateHome/>}/>
          <Route path="/modules" element={<Modules/>}/>
        </Route>
        <Route element={<PublicRoutes/>}>
          <Route path="/" element={<PublicHome/>}/>
          <Route path="/login" element={<Login/>}/>
          <Route path="/signup" element={<Signup/>}/>
        </Route>
      </Route>
    </Routes>
  )
}

路由守卫组件

PrivateRoutes.jsx

function PrivateRoutes ({children, ...rest}) {
  const {user} = UserAuth()
  if (user===undefined) return <Loading/>
  return (
    user ? <Outlet/>: <Navigate to="/login"/>
  )
}

PublicRoutes.jsx

import React from 'react'
import { Outlet, Navigate } from 'react-router-dom'
import Loading from '../components/Loading'
import { UserAuth } from './AuthContext'

function PublicRoutes ({children}) {
    const {user} = UserAuth()
    if (user===undefined) return <Loading/>
    return (
      user ? <Navigate to="/welcome"/> : <Outlet/>
    )
}

登录组件与认证上下文

Login.jsx

const handleLogin = async (e) => {
  e.preventDefault()
  try {
    await login(email, password)
    navigate("/modules")
  } catch (error) {
    console.log(error)
    setPassword("")
  }
}

AuthContext.jsx

const AuthContext = createContext()

export const AuthContextProvider = ({children})=> {
  const [user, setUser] = useState(undefined) // undefined -> loading状态

  const login = (email, password) => {
      return signInWithEmailAndPassword(auth, email, password)
  }

  useEffect(()=> {
   const unsubscribe = onAuthStateChanged(auth, async (currentUser) => {
    setUser(currentUser)
   })
   return ()=> {
    unsubscribe()
   }
 }, [])

  return (
    <AuthContext.Provider value={{user, login}}>
      {children}
    </AuthContext.Provider>
  ) 
}

export const UserAuth = () => {
 return useContext(AuthContext)
}

补充说明:普通navigate调用在其他场景下正常工作,仅在公共路由与私有路由切换时出现异常。


解决方案

核心问题分析

登录成功后,onAuthStateChanged会异步更新user状态,此时PublicRoutes检测到用户已登录,会触发重定向到/welcome,覆盖了登录时的navigate("/modules")操作。

具体修复步骤

  1. 修改PublicRoutes逻辑,允许已登录用户临时访问登录/注册页
    调整路由守卫逻辑,当用户已登录时,若当前处于登录或注册页则允许停留,否则再重定向:

    import React from 'react'
    import { Outlet, Navigate, useLocation } from 'react-router-dom'
    import Loading from '../components/Loading'
    import { UserAuth } from './AuthContext'
    
    function PublicRoutes ({children}) {
        const {user} = UserAuth()
        const location = useLocation()
        const allowedPublicPaths = ['/login', '/signup']
    
        if (user===undefined) return <Loading/>
    
        if (user) {
            // 已登录用户在登录/注册页时允许访问,否则重定向
            return allowedPublicPaths.includes(location.pathname) 
                ? <Outlet/> 
                : <Navigate to="/welcome"/>
        } else {
            return <Outlet/>
        }
    }
    
  2. 优化登录跳转,使用replace模式覆盖历史记录
    在登录成功后的跳转中加入replace: true,替换当前登录页的历史记录,避免后续重定向干扰:

    // Login.jsx中修改navigate调用
    navigate("/modules", { replace: true })
    

原理说明

  • 修改PublicRoutes后,已登录用户停留在登录/注册页时不会被强制重定向,确保登录流程中的跳转能顺利完成。
  • 使用replace: true会将登录页从历史栈中移除,即使后续有重定向触发,也不会回到登录页,同时保证目标页面成为当前活跃路由。

内容的提问来源于stack exchange,提问作者KidMe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 15:05:06