我可以在 Remix 中为单个 URL 处理多个加载器吗?

问题描述 投票:0回答:2

目前我有一个包含多个部分的登录页面,它是使用 Remix.run 构建的。这些部分是同一网址的一部分,它们在同一页面中垂直并排显示。

我的问题是页面加载持续了一段时间,因为在加载程序中完成了多个请求。每个部分需要来自服务器的不同信息,但所有部分的所有请求都在同一个加载器中等待。

我可以为每个部分处理一个装载机吗?所以整个页面不会等待所有请求完成,但每个部分都可以等待自己的数据

我已经尝试将每个部分作为一条路线处理

> routes
  > my-page.tsx
  > my page
    > section-1.tsx
    > section-2.tsx

然后我尝试为每个section添加一个loader,同样调用my-page.tsx中的sections

我的页面.tsx

const MyPage = (): React.ReactElement => (
  <main>
    <section>
      <Section1 />
    </section>
    <section>
      <Section2 />
    </section>
  </main>
)
export default MyPage;

但是我得到下一个错误

TypeError: Cannot destructure property 'myData' of '(0 , import_react7.useLoaderData)(...)' as it is undefined.

Section1 组件似乎试图从 MyPage 加载器获取数据,而不是从 Section1 加载器本身获取数据。

如果我在 MyPage 中使用

<Outlet />
组件,如果我通过 URL 访问它们,Section1 和 Section2 加载器就会工作

localhost:3000/my-page/section-1
localhost:3000/my-page/section-2

但我不希望这些部分是嵌套路线,我希望它们在我的页面中。

如果有人能帮助我,我将不胜感激。谢谢!

reactjs routes remix nested-routes remix.run
2个回答
3
投票

从技术上讲,每个 url 可以有多个加载器,但是它们只能由路由模块导出(路由模块代表单个 URL 段)。

无论如何,这无助于加快页面加载速度,因为必须在呈现页面之前解析所有加载器。

因此,我要做的第一件事是确认您的“部分”数据是并行请求的。

// 🚨 Avoid this (serial)
const loader = async () => {
   const section1 = await fetchSection1();
   const section2 = await fetchSection2();
   const section3 = await fetchSection3();
   return json({ section1, section2, section3 });
}
// ✅ Prefer this (parallel)
const loader = async () => {
   const [section1, section2, section3] = await Promise.all([
      fetchSection1(),
      fetchSection2()
      fetchSection3()
   ]);
   return json({ section1, section2, section3 });
}

如果还是很慢,下一步就是找出哪个部分用了很长时间。

如果有一个或两个调用特别慢,您最终将能够

defer
数据,允许它呈现回退直到准备就绪。

然而,在撰写本文时,此 React Router 功能尚未登陆 Remix

const loader = async () => {
  // Notice we don't await fetchSection3 (as it's been identified as slow)
  const section3 = fetchSection3();
  const [section1, section2] = await Promise.all([
    fetchSection1(),
    fetchSection2(),
  ]);
  return defer({
    section1,
    section2,
    section3, // Promise
  });
};

export default function Component() {
  const { section1, section2, section3 } = useLoaderData();
  return (
    <main>
      <section>
        <Section1 data={section1} />
      </section>
      <section>
        <Section2 data={section2} />
      </section>
      <section>
        <React.Suspense fallback={"Loading"}>
          <Await resolve={section3}>
            {(section3) => (
              <Section3 data={section3} />
            )}
          </Await>
        </React.Suspense>
      </section>
    </main>
  );
}

鉴于

defer
Remix 尚不支持。您现在可能不得不在客户端中创建一个资源路由
useFetcher

如果您发现所有部分都同样慢,您将需要加快您的数据库/API 调用。如果那不可能,您的下一个最佳选择是查看 http 或服务器端缓存


0
投票

在混音中,

routes
目录下的所有内容都将在浏览器中作为“导航路线”/URL 提供。

我会尝试使用

<Outlet />
而不是
<Section1 />
。查看 this remix documentation 关于 nested routing。我读过几次,有时回过头来提醒自己 Remix 是如何处理嵌套路由的。

如果您希望 Section1 和 Section2 出现在用户的同一路线上,您应该从

routes
文件夹以外的其他地方导入反应组件。您的部分可能作为单独的 React Functions 导入到您的路线中会更好。

app/routes/my-page.tsx

import { Section1, Section2 } from "~/components/sections.tsx"
// ~ is a reference to the app directory. `~/routes` is also a valid path

// this function will be loaded when the requests comes in
export const loader: LoaderFunction = async ({request}) => {
   const myData = await fetch(random_api)
   return json({myData})
}
// this function will be returned to the browser
export default function MyPageRoute() {
   const myData = useLoaderData()
   return(
     <main>
       <section>
         <Section1 data={myData.section1} />
       </section>
       <section>
         <Section2 data={myData.section2} />
       </section>
     </main>
   )
}

我总是为我的 React 组件使用 routes/ 目录的

outside
目录,我不希望它成为路由。希望这有帮助:)

编辑 - 忘记在反应组件中添加数据属性

© www.soinside.com 2019 - 2024. All rights reserved.