如何在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
相关产品推荐
相关产品推荐

