一、前言
useLoaderData
,用于在組件中獲取路由預加載的數據。它通常與路由配置中的 loader
函數配合使用,用于在頁面渲染前異步獲取數據(如 API 請求),并將數據直接注入組件,從而簡化數據流管理。
二、useLoaderData核心用途
預加載頁面數據:在路由匹配時自動觸發數據加載,減少組件渲染后的等待時間。
簡化組件邏輯:組件無需手動處理數據獲取和狀態管理。
支持服務端渲染 (SSR):與 React Router
的服務端渲染方案無縫集成。
數據共享:同一路由下的嵌套組件可直接訪問 loader
數據。
三、useLoaderData基本使用步驟
定義路由配置:在路由中聲明 loader
函數。
在組件中獲取數據:通過 useLoaderData()
讀取 loader
返回的數據。
四、示例:用戶信息頁面
4.1、 定義路由配置(使用 createBrowserRouter)
// 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 函數(異步獲取數據)
// src/UserPage.jsx
export async function userLoader({ params }) {// 從路由參數中獲取 userIdconst 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
// 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
類型定義明確數據類型:
// TypeScript 示例
const user = useLoaderData() as UserType;
6.4、錯誤處理
若 loader 拋出錯誤(如 throw new Response()
),需通過 React Router
的錯誤邊界處理。
示例:在路由配置中添加 errorElement:
{path: "/user/:userId",element: <UserPage />,loader: userLoader,errorElement: <ErrorPage />, // 自定義錯誤頁面
}
6.5、依賴關系
loader
在以下情況重新執行:
路由參數變化(如從 /user/1 跳轉到 /user/2)。
通過 useNavigation().formAction 或 useRevalidator()
手動觸發重新驗證。
七、高級用法:嵌套數據與重定向
7.1、 嵌套路由共享數據
// 父路由 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 中重定向
export async function authLoader({ request }) {const isLoggedIn = checkUserAuth();// 未登錄時重定向到登錄頁if (!isLoggedIn) {throw redirect("/login");}return fetchProtectedData();
}
八、完整案例:博客文章列表
8.1、 Loader 函數(獲取文章列表)
// src/routes/postsLoader.js
export async function postsLoader() {const response = await fetch("/api/posts");const posts = await response.json();return { posts };
}
8.2、路由配置
// src/main.jsx
const router = createBrowserRouter([{path: "/posts",element: <PostsPage />,loader: postsLoader,errorElement: <ErrorPage />,},
]);
8.3、 組件渲染
// 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
顯示加載動畫:
function PostsPage() {const { posts } = useLoaderData();const navigation = useNavigation();if (navigation.state === "loading") {return <Spinner />;}return /* 渲染文章列表 */;
}
useLoaderData,可以 實現數據加載與 UI 渲染的分離,讓代碼更清晰、更易維護。尤其適合中大型應用中需要統一管理數據請求的場景。