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

React Router路由加载时如何显示过渡加载页面?

解决React Router Loader加载耗时导致无反馈的问题

核心思路

放弃让路由loader阻塞导航的模式,改用defer异步加载+页面内Suspense兜底,实现即时跳转并在数据就绪前显示加载状态,直接解决你遇到的两个场景问题。

修复defer方案的正确用法

你之前尝试defer未生效,大概率是在loader中错误地await了异步请求,导致仍然阻塞导航。正确的做法是在loader中直接返回未解析的Promise,配合React Suspense实现页面内加载状态。

1. 修改路由配置

给路由添加id(方便后续获取loader数据),并使用defer返回异步请求的Promise:

import { createBrowserRouter, defer } from "react-router-dom";
import Dashboard from "./Dashboard";

// 你的异步请求函数
async function getData() {
  const res = await fetch("/api/dashboard");
  if (!res.ok) throw new Error("数据加载失败");
  return res.json();
}

const router = createBrowserRouter([
  {
    path: "/dashboard",
    element: <Dashboard />,
    id: "dashboard", // 添加路由ID
    loader: async () => {
      // 关键:不await getData,直接返回Promise
      return defer({
        dashboardData: getData(),
      });
    },
  },
]);

2. 改造Dashboard组件

用React Suspense包裹需要数据的渲染区域,设置加载状态的兜底UI,再通过useRouteLoaderData和React 18的use钩子获取异步数据:

import { Suspense } from "react";
import { useRouteLoaderData } from "react-router-dom";
import { use } from "react";

// 负责渲染数据的子组件
function DashboardContent() {
  const { dashboardData } = useRouteLoaderData("dashboard");
  // 使用use钩子解析Promise
  const data = use(dashboardData);

  return (
    <div className="dashboard-content">
      {/* 这里渲染你的数据内容 */}
      <h1>欢迎来到仪表盘</h1>
      <p>用户数据:{JSON.stringify(data)}</p>
    </div>
  );
}

// 主组件,处理加载状态
function Dashboard() {
  return (
    <div className="dashboard-container">
      {/* 即时显示加载状态,直到数据就绪 */}
      <Suspense fallback={<div className="loading">加载中...</div>}>
        <DashboardContent />
      </Suspense>
    </div>
  );
}

export default Dashboard;

针对两种场景的优化说明

  • 场景1:点击跳转按钮无反馈:确保使用React Router的Link组件(而非自定义的异步跳转逻辑),点击后会立即导航到/dashboard路由,页面会即时切换并显示Suspense的加载状态,不再停留在原页面等待数据。
    import { Link } from "react-router-dom";
    
    // 跳转按钮示例
    <Link to="/dashboard">进入仪表盘</Link>
    
  • 场景2:直接访问URL页面空白:访问/dashboard时,路由会立即渲染Dashboard组件,Suspense的fallback会即时显示加载状态,直到数据加载完成后替换为实际内容,彻底解决空白等待问题。

替代方案:手动管理加载状态

如果你不想使用Suspense,也可以在loader中返回包含加载状态的对象,手动在组件中处理:

// 路由loader
loader: async () => {
  return {
    dashboardData: getData(), // 返回Promise
  };
}

// Dashboard组件
function Dashboard() {
  const { dashboardData } = useLoaderData();
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    dashboardData
      .then(res => {
        setData(res);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }, [dashboardData]);

  if (loading) return <div className="loading">加载中...</div>;
  if (error) return <div className="error">{error}</div>;

  return <div>{/* 渲染数据 */}</div>;
}

这种方式更灵活,但代码量稍大,推荐优先使用Suspense+defer的方案,更符合React Router的设计理念。

内容的提问来源于stack exchange,提问作者Wamy-Dev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 03:01:30