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

React中JWT校验完成前阻止路由渲染及useNavigate优化

问题原因

当前代码出现登录页闪屏,核心是3个逻辑漏洞:

  • 缺少鉴权加载态:组件初始authorized默认值为false,首次挂载时会直接走分支渲染<Outlet />,登录/注册等子路由会先被渲染,等异步JWT校验接口返回后才触发跳转,中间的等待时间就会出现页面闪屏。
  • 鉴权函数调用位置错误:直接在组件渲染阶段调用authorize(),每次组件重渲染都会重复发起鉴权请求,异步状态更新还会触发无意义的多次重渲染。
  • 副作用逻辑位置错误:navigate跳转属于副作用,直接写在渲染判断分支里会导致渲染流程异常,触发React警告甚至重复跳转。

额外说明:React Router 提供的useNavigate默认就是客户端路由跳转,本身不会触发整页重载,如果出现跳转重载,一般是错误使用了<a>标签做站内跳转、跳转时传入了带域名的全量地址触发浏览器默认导航、或者路由配置嵌套错误导致的。

修复方案

1. 重写ProtectedRoute组件

核心改动:

  • 新增三态鉴权状态(加载中/已授权/未授权),初始状态为加载中,鉴权请求完成前只返回加载占位,不渲染任何子路由,从根源避免闪屏
  • 把鉴权逻辑、跳转逻辑全部放到useEffect中,仅在组件挂载、token变化时执行一次,避免重复调用接口
  • 跳转时加replace: true配置,避免已登录用户点击浏览器回退时再次回到登录页触发循环跳转
import { useState, useContext, useEffect } from "react";
import { useNavigate, Outlet } from "react-router-dom";
import AuthContext from "../Context/AuthProvider";

const ProtectedRoute = ({ access }) => {
  const [authStatus, setAuthStatus] = useState('loading');
  const { auth } = useContext(AuthContext);
  const navigate = useNavigate();

  useEffect(() => {
    const checkAuth = async () => {
      // 本地无token直接判定为未授权,不用发请求
      if (!auth.accessToken) {
        setAuthStatus('unauthorized');
        return;
      }
      try {
        await access(auth.accessToken);
        setAuthStatus('authorized');
      } catch (err) {
        setAuthStatus('unauthorized');
      }
    };

    checkAuth();
  }, [auth.accessToken, access]);

  useEffect(() => {
    if (authStatus === 'authorized') {
      navigate('/', { replace: true });
    }
  }, [authStatus, navigate]);

  // 鉴权未完成时只显示加载态,可替换为项目全局加载组件、骨架屏
  if (authStatus === 'loading') {
    return <div className="global-loading">校验登录状态中...</div>;
  }

  // 仅未授权状态下渲染登录/注册等子路由
  if (authStatus === 'unauthorized') {
    return <Outlet />;
  }

  return null;
};

export default ProtectedRoute;

2. useNavigate避免页面重载的注意事项

只要遵循以下规则,useNavigate只会做客户端无刷新路由切换:

  • 站内跳转不要用原生<a href="/xxx">标签,统一用React Router的<Link>组件或者navigate方法
  • 站内跳转只传相对路径,比如写navigate('/login'),不要写带域名的全量地址触发浏览器默认导航
  • 不要重复嵌套同路径路由配置,避免路由匹配逻辑异常

补充说明

现有App.js中的路由配置不需要改动,替换ProtectedRoute组件后,JWT校验请求返回前不会渲染任何登录/注册页面,效果和之前EJS服务端中间件拦截完全一致:校验不通过才渲染对应路由,校验通过直接拦截跳转。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 01:21:46