React Router v6.9.0中useLoaderData能否在兄弟组件使用及实现方案
问题解答
关于useLoaderData的使用范围
没错,useLoaderData只能在配置了对应loader的路由所渲染的组件,以及该组件的所有后代组件中使用。你这里的Genre1、Genre2是和MoviePage同级的路由组件,属于不同的路由分支,既不是MoviePage的后代,自身也没有配置loader,所以调用useLoaderData自然会返回undefined。
让Genre组件获取loader数据的几种方案
方案1:将loader移到父路由
把数据请求的loader配置到/movies对应的父路由(也就是Root2所在的路由),这样所有子路由的组件(包括MoviePage、Genre1、Genre2等)都能直接通过useLoaderData拿到数据。
修改后的路由示例:
const router = createBrowserRouter([ { path: "/", element: <Root />, children: [ { index: true, element: <HomePage />, }, { path: "movies", element: <Root2 />, // 把loader移到父路由 loader: async () => { const options = { method: "GET", url: "https://ott-details.p.rapidapi.com/advancedsearch", params: { start_year: "1970", end_year: "2020", min_imdb: "6", max_imdb: "10", genre: "action", language: "english", type: "movie", sort: "latest", page: "1", }, headers: { "X-RapidAPI-Key": "{api-key}", "X-RapidAPI-Host": "ott-details.p.rapidapi.com", }, }; try { const response = await axios.request(options); return response.data; } catch (err) { console.error("数据请求失败:", err); throw new Response("加载失败", { status: 500 }); } }, children: [ { index: true, element: <MoviePage />, // 移除这里的loader }, { path: "Genre1", element: <Genre1 /> }, { path: "Genre2", element: <Genre2 /> }, { path: "Genre3", element: <Genre3 /> }, { path: ":genre/:movieId", element: <MovieDetail /> }, ], }, ], }, ]);
方案2:用useRouteLoaderData指定获取目标路由的loader数据
给配置了loader的MoviePage路由添加一个唯一id,然后在Genre组件中通过useRouteLoaderData(id)来获取该路由的loader返回值。
步骤1:修改路由,给MoviePage的路由加id:
{ index: true, element: <MoviePage />, id: "movieListLoader", // 添加唯一id loader: async () => { // 原loader逻辑 }, }
步骤2:在Genre组件中调用:
import { useRouteLoaderData } from "react-router-dom"; function Genre1() { const movieData = useRouteLoaderData("movieListLoader"); // 接下来就可以使用movieData了 return <div>{/* 渲染内容 */}</div>; }
方案3:给每个Genre路由单独配置loader(更贴合业务场景)
如果不同Genre需要对应不同类别的电影数据,更合理的做法是给每个Genre路由配置自己的loader,根据genre参数请求对应数据。
示例:
{ path: "Genre1", element: <Genre1 />, loader: async () => { const options = { // ... 基础配置 params: { // ... 其他参数 genre: "action", // 这里换成Genre1对应的类别 }, }; try { const response = await axios.request(options); return response.data; } catch (err) { console.error(err); throw new Response("加载失败", { status: 500 }); } }, }
额外提示:修正loader中的响应判断逻辑
你当前的loader里用!response.ok判断请求状态是错误的——axios的响应对象里没有ok属性,它会在请求失败(状态码≥400)时直接抛出异常,所以应该用try/catch包裹请求逻辑,更符合axios的使用规范,如上面方案中的代码所示。
内容的提问来源于stack exchange,提问作者Kshitij Verma
相关产品推荐
相关产品推荐

