React Apollo GraphQL:如何在组件间共享数据转换逻辑
解决Apollo GraphQL React应用中重复数据转换的问题
方案1:封装带缓存转换逻辑的自定义Hook
将查询与高成本的转换逻辑封装到自定义Hook中,借助useMemo缓存转换结果,只有当原始查询数据更新时才重新执行转换。多个组件调用该Hook时会共享缓存后的转换值。
import { useQuery, gql } from '@apollo/client'; import { useMemo } from 'react'; // 定义GraphQL查询 const GET_DATA_QUERY = gql` query GetData { items { id rawField1 rawField2 } } `; // 高成本的转换函数 const transformRawData = (rawData) => { return rawData.items.map(item => ({ id: item.id, combinedField: `${item.rawField1}_${item.rawField2}`, // 其他复杂转换逻辑... })); }; // 自定义Hook export const useTransformedData = () => { const { data, loading, error } = useQuery(GET_DATA_QUERY); // 缓存转换结果,仅当data变化时重新计算 const transformedData = useMemo(() => { if (!data) return []; return transformRawData(data); }, [data]); return { transformedData, loading, error }; };
组件中直接使用该Hook即可:
// 组件A const ComponentA = () => { const { transformedData, loading } = useTransformedData(); if (loading) return <div>Loading...</div>; return ( <div> {transformedData.map(item => ( <div key={item.id}>{item.combinedField}</div> ))} </div> ); }; // 组件B调用同一个Hook,自动共享转换结果
方案2:利用Apollo缓存存储派生字段
通过Apollo Client的typePolicies配置,将转换后的值定义为缓存中的派生字段,让Apollo自动处理转换逻辑并缓存结果,所有查询该字段的组件都会共享缓存值。
首先修改查询,添加@client标记的本地派生字段:
query GetData { items { id rawField1 rawField2 combinedField @client # 本地派生字段 } }
然后配置Apollo Client的缓存策略:
import { ApolloClient, InMemoryCache } from '@apollo/client'; const client = new ApolloClient({ uri: '/your-graphql-endpoint', cache: new InMemoryCache({ typePolicies: { Item: { fields: { combinedField: { // 基于原始字段生成转换后的值,仅当原始字段变化时重新计算 read(_, { readField }) { const raw1 = readField('rawField1'); const raw2 = readField('rawField2'); return `${raw1}_${raw2}`; // 替换为你的实际转换逻辑 } } } } } }) });
此后任何组件查询combinedField时,Apollo都会直接从缓存读取转换后的值,无需重复执行转换。
方案3:通过React Context共享转换后的数据
如果需要共享数据的组件分散在不同层级,可以将查询与转换逻辑放在顶层Provider中,通过Context向下传递转换后的数据。
import { createContext, useContext, useQuery, useMemo } from 'react'; import { gql } from '@apollo/client'; const DataContext = createContext(null); // 顶层Provider组件 export const DataProvider = ({ children }) => { const { data, loading, error } = useQuery(GET_DATA_QUERY); const transformedData = useMemo(() => { if (!data) return []; return transformRawData(data); }, [data]); return ( <DataContext.Provider value={{ transformedData, loading, error }}> {children} </DataContext.Provider> ); }; // 自定义Hook用于获取Context数据 export const useSharedData = () => useContext(DataContext);
在App中包裹需要数据的组件:
import { DataProvider } from './DataProvider'; function App() { return ( <DataProvider> <ComponentA /> <ComponentB /> {/* 其他需要数据的组件 */} </DataProvider> ); }
组件中使用:
const ComponentB = () => { const { transformedData, loading } = useSharedData(); if (loading) return <div>Loading...</div>; // 渲染逻辑 };
内容的提问来源于stack exchange,提问作者BladesV
相关产品推荐
相关产品推荐

