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

在React Remix中使用Fetcher实现数据加载更多的正确方式

在Remix中实现产品列表加载更多的正确方式

你的代码核心问题是:使用fetcher.load发起加载更多请求后,没有读取fetcher返回的新数据来更新列表——useLoaderData只会拿到页面初始加载的数据,不会自动同步fetcher请求的结果。另外你的loader还有参数解构错误,先一步步修复:

1. 修复Loader的基础错误

原loader里没有解构request参数,导致request.url会报错,同时要把offset转为数字类型避免接口出错:

export async function loader({ request, context }: LoaderFunctionArgs) {
  const url = new URL(request.url);
  const offset = Number(url.searchParams.get("offset")) || 0;

  const { products, count } = await getProducts({
    limit: 10,
    offset,
  });

  return {
    products,
    totalCount: count.aggregate?.count,
  };
}

2. 正确处理Fetcher加载的新数据

在组件中需要从fetcher.data获取新加载的产品,合并到现有列表,同时处理加载状态和重复请求:

export default function UploadProductsRoute() {
  const { products: initialProducts, totalCount } = useLoaderData<typeof loader>();
  const fetcher = useFetcher();
  const fetchers = useFetchers();

  // 处理表单提交的乐观更新数据
  const optimisticProducts = fetchers.reduce<typeof initialProducts>((memo, f) => {
    if (f.formData) {
      const data = Object.fromEntries(f.formData) as typeof initialProducts[0];
      // 避免重复添加已存在的产品
      if (!memo.some(item => item.id === data.id) && !initialProducts.some(item => item.id === data.id)) {
        memo.push(data);
      }
    }
    return memo;
  }, []);

  // 合并初始数据、乐观更新数据、加载更多的新数据
  let products = [...initialProducts, ...optimisticProducts];
  if (fetcher.data && fetcher.data.products) {
    // 过滤重复项,避免乐观更新后fetcher返回重复数据
    const newProducts = fetcher.data.products.filter(
      item => !products.some(p => p.id === item.id)
    );
    products = [...products, ...newProducts];
  }

  // 判断是否还有更多数据可加载
  const hasMore = products.length < (totalCount || 0);
  // 加载状态判断
  const isLoading = fetcher.state === "loading";

  return (
    <div>
      <div>
        <div>
          <h1>添加产品</h1>
        </div>
        <AddProductForm />
        <div>
          <h1>已添加的产品</h1>
        </div>
        <div>
          <div>
            {products.map((product) => (
              <ProductItem 
                key={product.id} 
                name={product.name} 
                description={product.description} 
              />
            ))}
            {/* 加载中提示 */}
            {isLoading && <div>加载中...</div>}
          </div>
        </div>
        <div>
          {/* 仅当有更多数据且未加载时显示按钮 */}
          {hasMore && !isLoading && (
            <Button onClick={() => { 
              fetcher.load(`?offset=${products.length}`);
            }}>
              加载更多
            </Button>
          )}
        </div>
      </div>
    </div>
  );
}

关键修复点说明

  • 读取fetcher.data:fetcher.load请求完成后,新数据会存在fetcher.data中,需要手动合并到现有列表。
  • 避免重复数据:不管是乐观更新还是加载更多,都要过滤已存在的产品,防止列表出现重复项。
  • 加载状态控制:通过fetcher.state判断加载状态,禁用按钮或显示提示,避免重复请求。
  • 是否还有更多数据:用当前列表长度和总产品数对比,决定是否显示「加载更多」按钮。

内容的提问来源于stack exchange,提问作者Joseph

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 12:02:14