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

如何在独立组件中正确实现Remix延迟数据流式加载?

问题分析

你遇到的核心问题有两个:

  1. Remix 组件不能直接定义 loader:loader 是 Remix 路由页面专属的API,独立组件中定义 loader 会导致服务端专属模块(如 auth.server)被打包到客户端代码中,触发 Vite 的编译报错。
  2. 代码逻辑存在细节错误:原代码中 collections.products.findMany 未加 await、Await 回调参数与渲染变量名不匹配,这些也会导致功能异常。
解决方案

针对独立组件的流式加载需求,提供三种可行方案:

方案一:页面路由处理数据,组件接收延迟加载值

将数据获取逻辑移到父页面的 loader 中,通过 defer 返回延迟加载的 Promise,再传递给组件渲染。

1. 父页面路由代码(如 app/routes/landing.tsx)

import { defer } from "@remix-run/node";
import { auth } from "~/services/auth.server";
import Products from "~/components/Landing/Products";
import { Await, useLoaderData } from "@remix-run/react";
import { Suspense } from "react";

export const loader = async ({ request }: LoaderFunctionArgs) => {
  const user = await auth.isAuthenticated(request);
  // 将数据库查询包装为Promise,交给defer处理流式加载
  const productsPromise = collections.products.findMany({ 
    userId: user?._id 
  });
  
  return defer({ products: productsPromise });
};

export default function LandingPage() {
  const { products } = useLoaderData<typeof loader>();
  
  return (
    <div>
      {/* 页面其他内容 */}
      <Suspense fallback={<div>LOADING PRODUCTS...</div>}>
        <Await resolve={products}>
          {(products) => <Products products={products} />}
        </Await>
      </Suspense>
    </div>
  );
}

2. 独立组件代码(app/components/Landing/Products.tsx)

import Product from "./Product";

// 定义产品类型(根据你的数据结构调整)
type ProductType = {
  _id: string;
  // 其他产品字段
};

export default function Products({ products }: { products: ProductType[] }) {
  return (
    <div className="container">
      {products.map((product) => (
        <Product key={product._id} product={product} />
      ))}
    </div>
  );
}

方案二:使用 Remix 服务器组件(v2+ 支持)

如果你的 Remix 版本支持服务器组件,可以直接将组件改为服务器组件,无需担心服务端模块被打包到客户端,同时天然支持流式渲染。

服务器组件代码(app/components/Landing/Products.server.tsx)

import { auth } from "~/services/auth.server";
import Product from "./Product";

type ProductType = {
  _id: string;
  // 其他产品字段
};

// 服务器组件:仅在服务端执行,不会被客户端 hydration
export default async function Products({ request }: { request: Request }) {
  const user = await auth.isAuthenticated(request);
  const products = await collections.products.findMany({ 
    userId: user?._id 
  });
  
  return (
    <div className="container">
      {products.map((product) => (
        <Product key={product._id} product={product} />
      ))}
    </div>
  );
}

页面中使用服务器组件

// 父页面路由代码
import Products from "~/components/Landing/Products.server";

export default function LandingPage() {
  return (
    <div>
      {/* 页面其他内容 */}
      <Products request={request} />
    </div>
  );
}

注意:服务器组件不能使用客户端 Hooks(如 useState、useLoaderData),仅用于服务端数据获取与静态渲染。

方案三:客户端通过 API 路由获取数据

如果必须在客户端组件中处理数据获取,可通过 Remix API 路由封装服务端逻辑,组件用 useFetcher 发起请求。

1. API 路由代码(app/routes/api/products.tsx)

import { json } from "@remix-run/node";
import { auth } from "~/services/auth.server";

export const loader = async ({ request }: LoaderFunctionArgs) => {
  const user = await auth.isAuthenticated(request);
  const products = await collections.products.findMany({ 
    userId: user?._id 
  });
  
  return json(products);
};

2. 客户端组件代码

import { useFetcher } from "@remix-run/react";
import { useState, useEffect } from "react";
import Product from "./Product";

type ProductType = {
  _id: string;
  // 其他产品字段
};

export default function Products() {
  const fetcher = useFetcher();
  const [products, setProducts] = useState<ProductType[]>([]);

  useEffect(() => {
    fetcher.load("/api/products");
  }, [fetcher]);

  if (fetcher.state === "loading") {
    return <div>LOADING PRODUCTS...</div>;
  }

  if (fetcher.data) {
    setProducts(fetcher.data);
  }

  return (
    <div className="container">
      {products.map((product) => (
        <Product key={product._id} product={product} />
      ))}
    </div>
  );
}
原代码问题总结
  1. 独立组件中定义 loader 违反 Remix 架构规则,导致服务端模块泄漏到客户端。
  2. collections.products.findMany 未添加 await,无法正确获取数据。
  3. Await 回调参数为 products,但渲染时使用未定义的 product 变量,会触发运行时错误。

内容的提问来源于stack exchange,提问作者Alex G.P.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 09:38:13