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

React JS中创建受保护路由:登录后导航失效问题求助

问题解决:React受保护路由登录后无法跳转

问题根源

  1. 状态未同步:你的isLoggedIn状态仅在组件挂载时通过useEffect初始化一次,登录成功后localStorage存入了token,但状态没有更新,导致路由判断仍然是false,页面停留在登录页。
  2. 路由判断逻辑不够健壮:直接在Route的element中写三元表达式,状态更新不及时会导致路由无法正确渲染。

解决方案

1. 封装可复用的ProtectedRoute组件

把权限校验逻辑抽成独立组件,同时监听localStorage变化确保状态同步:

import { useState, useEffect } from 'react';
import { Navigate } from 'react-router-dom';

const ProtectedRoute = ({ children }) => {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  useEffect(() => {
    const checkAuthStatus = () => {
      const token = localStorage.getItem('token');
      setIsLoggedIn(!!token);
    };

    // 初始化时校验
    checkAuthStatus();
    // 监听localStorage变化(登录/登出时触发)
    window.addEventListener('storage', checkAuthStatus);

    return () => window.removeEventListener('storage', checkAuthStatus);
  }, []);

  // 可选:添加加载状态避免页面闪烁
  if (isLoggedIn === null) {
    return <div>加载中...</div>;
  }

  return isLoggedIn ? children : <Navigate to='/login' />;
};

2. 修改路由配置使用ProtectedRoute

替换原来的路由写法,让受保护路由通过封装好的组件校验:

<Route path='/login' element={<Login />} />
<Route path='/signup' element={<SignUp />} />
<Route 
  path='/casting/calls/creation' 
  element={
    <ProtectedRoute>
      <CastingCallsCreation />
    </ProtectedRoute>
  } 
/>
<Route 
  path='/user/film/booth' 
  element={
    <ProtectedRoute>
      <UserFilmPitchingBooth />
    </ProtectedRoute>
  } 
/>

3. 完善登录组件的跳转逻辑

登录成功后,确保更新状态并正确跳转:

import { useNavigate } from 'react-router-dom';

const Login = () => {
  const navigate = useNavigate();

  const handleLogin = async () => {
    try {
      // 调用你的登录API
      const response = await fetch('/api/login', {
        method: 'POST',
        body: JSON.stringify(yourLoginData),
        headers: { 'Content-Type': 'application/json' }
      });
      const data = await response.json();

      if (response.ok) {
        // 存入token
        localStorage.setItem('token', data.token);
        // 手动触发storage事件,让ProtectedRoute更新状态
        window.dispatchEvent(new Event('storage'));
        // 跳转目标页面
        navigate('/casting/calls/creation', { replace: true });
      }
    } catch (error) {
      console.error('登录失败:', error);
    }
  };

  return (
    // 你的登录表单结构
    <div>
      {/* 表单输入项 */}
      <button onClick={handleLogin}>登录</button>
    </div>
  );
};

进阶优化:用Context管理全局登录状态

如果项目规模较大,推荐用Context统一管理登录状态,避免重复逻辑:

// AuthContext.js
import { createContext, useContext, useState, useEffect } from 'react';

const AuthContext = createContext();

export const AuthProvider = ({ children }) => {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  useEffect(() => {
    const token = localStorage.getItem('token');
    setIsLoggedIn(!!token);
  }, []);

  // 统一登录方法
  const login = (token) => {
    localStorage.setItem('token', token);
    setIsLoggedIn(true);
  };

  // 统一登出方法
  const logout = () => {
    localStorage.removeItem('token');
    setIsLoggedIn(false);
  };

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

export const useAuth = () => useContext(AuthContext);

然后修改ProtectedRoute和Login组件:

// 更新ProtectedRoute
import { useAuth } from './AuthContext';

const ProtectedRoute = ({ children }) => {
  const { isLoggedIn } = useAuth();
  return isLoggedIn ? children : <Navigate to='/login' />;
};

// 更新Login组件
import { useNavigate } from 'react-router-dom';
import { useAuth } from './AuthContext';

const Login = () => {
  const navigate = useNavigate();
  const { login } = useAuth();

  const handleLogin = async () => {
    try {
      const response = await fetch('/api/login', { /* 请求配置 */ });
      const data = await response.json();
      if (response.ok) {
        login(data.token);
        navigate('/casting/calls/creation', { replace: true });
      }
    } catch (error) {
      console.error('登录失败:', error);
    }
  };

  // ...表单结构
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 13:34:50