React 第四十二节 Router 中useLoaderData的用途详解

一、前言

useLoaderData,用于在组件中获取路由预加载的数据 。它通常与路由配置中的 loader 函数配合使用,用于在页面渲染前异步获取数据(如 API 请求),并将数据直接注入组件,从而简化数据流管理。

二、useLoaderData核心用途

预加载页面数据 :在路由匹配时自动触发数据加载,减少组件渲染后的等待时间。 简化组件逻辑 :组件无需手动处理数据获取和状态管理。 支持服务端渲染 (SSR) :与 React Router 的服务端渲染方案无缝集成。 数据共享 :同一路由下的嵌套组件可直接访问 loader 数据。

三、useLoaderData基本使用步骤

定义路由配置 :在路由中声明 loader 函数。 在组件中获取数据 :通过 useLoaderData() 读取 loader 返回的数据。

四、示例:用户信息页面

4.1、 定义路由配置(使用 createBrowserRouter)

javascript 复制代码
// src/main.jsx
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import UserPage, { userLoader } from "./UserPage";

const router = createBrowserRouter([
  {
    path: "/user/:userId",
    element: <UserPage />,
    loader: userLoader, // 数据预加载函数
  },
]);

ReactDOM.createRoot(document.getElementById("root")).render(
  <RouterProvider router={router} />
);

4.2 定义 Loader 函数(异步获取数据)

javascript 复制代码
// src/UserPage.jsx
export async function userLoader({ params }) {
  // 从路由参数中获取 userId
  const userId = params.userId;

  try {
    // 模拟 API 请求
    const response = await fetch(`/api/users/${userId}`);
    if (!response.ok) throw new Error("用户不存在");
    const userData = await response.json();
    return userData; // 返回的数据会被 useLoaderData() 接收
  } catch (error) {
    // 抛出错误,由 React Router 错误边界处理
    throw new Response("加载用户数据失败", { status: 404 });
  }
}

4.3、 在组件中使用 useLoaderData

javascript 复制代码
// src/UserPage.jsx
import { useLoaderData } from "react-router-dom";

export default function UserPage() {
  // 直接获取 loader 返回的数据
  const user = useLoaderData();

  return (
    <div>
      <h1>用户信息</h1>
      <p>姓名:{user.name}</p>
      <p>邮箱:{user.email}</p>
      <img src={user.avatar} alt="用户头像" />
    </div>
  );
}

五、参数与返回值

参数:无。

返回值:由当前路由的 loader 函数返回的数据(类型不限)。

六、注意事项

6.1、必须与路由 loader 绑定

只有在路由配置中定义了 loader,useLoaderData 才能获取到数据。

6.2、数据作用域

数据与当前路由关联,切换路由时数据会自动更新。

6.3、类型安全

默认情况下,useLoaderData 返回 unknown 类型(TypeScript)。建议通过类型断言loader 类型定义明确数据类型:

javascript 复制代码
// TypeScript 示例
const user = useLoaderData() as UserType;

6.4、错误处理

若 loader 抛出错误(如 throw new Response()),需通过 React Router 的错误边界处理。

示例:在路由配置中添加 errorElement:

javascript 复制代码
{
  path: "/user/:userId",
  element: <UserPage />,
  loader: userLoader,
  errorElement: <ErrorPage />, // 自定义错误页面
}

6.5、依赖关系

loader 在以下情况重新执行:

路由参数变化(如从 /user/1 跳转到 /user/2)。

通过 useNavigation().formAction 或 useRevalidator() 手动触发重新验证。

七、高级用法:嵌套数据与重定向

7.1、 嵌套路由共享数据

javascript 复制代码
// 父路由 loader
export async function parentLoader() {
  return { appVersion: "1.0.0" };
}

// 子路由组件中可直接访问父级 loader 数据
function ChildComponent() {
  const parentData = useLoaderData(); // 获取父路由的 loader 数据
  return <div>版本:{parentData.appVersion}</div>;
}

7.2、 在 Loader 中重定向

javascript 复制代码
export async function authLoader({ request }) {
  const isLoggedIn = checkUserAuth();

  // 未登录时重定向到登录页
  if (!isLoggedIn) {
    throw redirect("/login");
  }

  return fetchProtectedData();
}

八、完整案例:博客文章列表

8.1、 Loader 函数(获取文章列表)

javascript 复制代码
// src/routes/postsLoader.js
export async function postsLoader() {
  const response = await fetch("/api/posts");
  const posts = await response.json();
  return { posts };
}

8.2、路由配置

javascript 复制代码
// src/main.jsx
const router = createBrowserRouter([
  {
    path: "/posts",
    element: <PostsPage />,
    loader: postsLoader,
    errorElement: <ErrorPage />,
  },
]);

8.3、 组件渲染

javascript 复制代码
// src/PostsPage.jsx
import { useLoaderData } from "react-router-dom";

export default function PostsPage() {
  const { posts } = useLoaderData();

  return (
    <div>
      <h1>所有文章</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>
            <h2>{post.title}</h2>
            <p>{post.excerpt}</p>
          </li>
        ))}
      </ul>
    </div>
  );
}

十、最佳实践

10.1、分离数据逻辑

loader 函数单独放在 routes/ 目录中,保持组件专注于渲染。

10.2、缓存与优化

使用 shouldRevalidate 控制数据重新加载条件,避免不必要的请求。

10.3、加载状态提示

配合 useNavigation 显示加载动画:

javascript 复制代码
function PostsPage() {
  const { posts } = useLoaderData();
  const navigation = useNavigation();

  if (navigation.state === "loading") {
    return <Spinner />;
  }

  return /* 渲染文章列表 */;
}

useLoaderData,可以 实现数据加载与 UI 渲染的分离,让代码更清晰、更易维护。尤其适合中大型应用中需要统一管理数据请求的场景。

相关推荐
漂流瓶jz1 小时前
Webpack中各种devtool配置的含义与SourceMap生成逻辑
前端·javascript·webpack
前端架构师-老李1 小时前
React 中 useCallback 的基本使用和原理解析
前端·react.js·前端框架
木易 士心2 小时前
CSS 中 `data-status` 的使用详解
前端·css
明月与玄武2 小时前
前端缓存战争:回车与刷新按钮的终极对决!
前端·缓存·回车 vs 点击刷新
牧马少女2 小时前
css 画一个圆角渐变色边框
前端·css
zy happy2 小时前
RuoyiApp 在vuex,state存储nickname vue2
前端·javascript·小程序·uni-app·vue·ruoyi
小雨青年2 小时前
Cursor 项目实战:AI播客策划助手(二)—— 多轮交互打磨播客文案的技术实现与实践
前端·人工智能·状态模式·交互
小光学长3 小时前
基于Vue的儿童手工创意店管理系统as8celp7(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
前端·数据库·vue.js
meichaoWen3 小时前
【Vue】Vue框架的基础知识强化
前端·javascript·vue.js
jingling5553 小时前
Flutter | 基础环境配置和创建flutter项目
前端·flutter