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

如何在Relay中使用部分缓存数据?跨页面缓存复用疑问

在Relay中利用缓存数据实现部分内容优先渲染

你遇到的问题核心在于:usePreloadedQuery 默认会等待整个查询的所有字段都加载完成才会返回结果,即使部分字段已经存在于缓存中。要实现「先显示缓存数据,同时加载新字段」的效果,需要结合Relay的查询拆分能力和React的局部Suspense控制,具体方案如下:

方案1:拆分查询 + 局部Suspense包裹

将Screen B的查询拆分为「已有缓存的products」和「需要新请求的menus」两部分,用React Suspense单独包裹新请求的组件,避免全局挂起。

步骤1:抽复用的Products Fragment

先把products的查询逻辑抽成可复用的Fragment,确保Screen A和Screen B使用完全一致的字段定义:

const ProductsFragment = graphql`
  fragment ProductsFragment on Query {
    products(first: 5, channel: "default-channel") {
      edges {
        node {
          id
          name
          description
        }
      }
    }
  }
`;

// Screen A 复用该Fragment
const ProductsPageQuery = graphql`
  query products_PageQuery {
    ...ProductsFragment
  }
`;

步骤2:Screen B拆分查询逻辑

Screen B中,先用usePreloadedQuery获取缓存的products数据(直接从Relay Store读取,无网络请求),再用useLazyLoadQuery单独请求menus,并用Suspense包裹这部分组件:

// 单独定义menus的查询
const MenusQuery = graphql`
  query menus_MenusQuery {
    menus(first: 5) {
      edges {
        node {
          id
          name
          slug
        }
      }
    }
  }
`;

// 封装menus的加载组件
const MenusComponent = () => {
  const { menus } = useLazyLoadQuery(
    MenusQuery,
    {},
    { fetchPolicy: 'store-or-network' } // 优先读缓存,无缓存则请求
  );
  return <pre>{JSON.stringify(menus, null, 2)}</pre>;
};

// Screen B主组件
const Page = ({ preloadedQuery }: RelayProps<{}, typeof ProductsPageQuery>) => {
  const { products } = usePreloadedQuery(ProductsPageQuery, preloadedQuery);

  return (
    <div>
      <code>menus page</code>
      {/* 直接渲染缓存的products */}
      <pre>{JSON.stringify(products, null, 2)}</pre>
      {/* 局部Suspense包裹menus加载,仅这部分显示加载器 */}
      <Suspense fallback={<div>加载菜单中...</div>}>
        <MenusComponent />
      </Suspense>
    </div>
  );
};

方案2:用useFragment直接读取缓存数据

如果Screen B不需要预加载menus,也可以直接通过useFragment从Relay缓存中读取products数据,主查询只请求menus:

// Screen B的查询仅请求menus
const MenusPageQuery = graphql`
  query menus_PageQuery {
    menus(first: 5) {
      edges {
        node {
          id
          name
          slug
        }
      }
    }
  }
`;

const Page = ({ preloadedQuery }: RelayProps<{}, menus_PageQuery>) => {
  const { menus } = usePreloadedQuery(MenusPageQuery, preloadedQuery);
  // 直接从缓存读取products数据,无需额外请求
  const { products } = useFragment(ProductsFragment, { __typename: "Query" });

  return (
    <div>
      <code>menus page</code>
      <pre>{JSON.stringify(products, null, 2)}</pre>
      <pre>{JSON.stringify(menus, null, 2)}</pre>
    </div>
  );
};

注意:这种方式需要确保products数据已经存在于缓存中(比如从Screen A导航过来的场景),如果缓存中没有数据,useFragment会抛出错误,建议配合错误边界使用。

原理说明

  • Relay的usePreloadedQuery设计为「等待全查询就绪」,目的是保证组件渲染时所有数据都可用;
  • 通过拆分查询或Fragment复用,我们将已有缓存的数据和新请求的数据分离,再结合React的<Suspense>实现局部加载状态,避免全局挂起;
  • 这不是单纯的React层面延迟,而是Relay缓存能力与React Suspense的结合方案,既利用了Relay的缓存避免重复请求,又精准控制了加载UI的范围。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 08:30:00