如何在Apollo Client中实现派生计算值,优化数据查找效率
Apollo Client实现基于服务端数据的派生Map结构方案
以下三种方案均无需手动维护派生值,refetchQueries更新原始服务端数据后会自动触发重新计算,匹配你需要的类似reselect/@computed的能力:
方案1:缓存字段策略(最推荐,全局生效)
该方案不需要添加@client指令,也不需要手动维护变量,完美匹配你基于服务端原始数据计算派生值的需求。利用Apollo Client内置的Field Policy的read函数,在读取缓存字段时自动完成Map转换,完全基于服务端返回的原始数据计算,不需要修改查询语句或手动更新:
import { InMemoryCache, ApolloClient } from '@apollo/client'; const cache = new InMemoryCache({ typePolicies: { // 替换为你查询返回的父类型,通常为Query或自定义业务类型 Query: { fields: { // 替换为你要转换的列表字段名,例如goodsList、userList targetListField: { read(existingRawData) { if (!existingRawData) return undefined; // 自定义Map的key,示例用id,可根据业务调整 return new Map(existingRawData.map(item => [item.id, item])); } } } } } }); // 初始化client时传入上述cache即可 const client = new ApolloClient({ cache, uri: '你的接口地址' });
使用方式:原有查询逻辑无需任何修改,useQuery返回的data.targetListField直接就是转换完成的Map结构。
方案2:记忆化自定义Hook(灵活适用单一场景)
如果不想修改全局缓存配置,可以封装带useMemo的自定义Hook,只在用到对应计算值的组件中生效:
import { useQuery, useMemo } from '@apollo/client'; import { yourQuery } from './queryDefs'; // 公共Hook可多组件复用 function useTargetListMap(queryVariables = {}) { const { data, ...queryRest } = useQuery(yourQuery, { variables: queryVariables }); const targetMap = useMemo(() => { const rawList = data?.targetListField || []; return new Map(rawList.map(item => [item.id, item])); }, [data?.targetListField]); return { targetMap, rawData: data, ...queryRest }; }
使用方式:在组件中直接调用useTargetListMap即可拿到转换后的Map,原始数据更新时useMemo会自动重新计算。
方案3:搭配reselect实现复杂派生逻辑
如果有多个派生值、或者需要和Redux开发习惯保持一致,可以直接引入reselect配合自定义Hook使用,二者完全兼容:
import { createSelector } from '@reduxjs/toolkit'; // 或独立reselect包 import { useQuery } from '@apollo/client'; import { yourQuery } from './queryDefs'; // 定义可复用的选择器 const selectRawList = (queryData) => queryData?.targetListField || []; const selectTargetMap = createSelector( [selectRawList], (rawList) => new Map(rawList.map(item => [item.id, item])) ); // 可扩展更多派生值选择器,例如按状态筛选的列表、计数等 function useTargetListData(queryVariables = {}) { const { data, ...queryRest } = useQuery(yourQuery, { variables: queryVariables }); const targetMap = selectTargetMap(data); // 可同时返回其他派生值 return { targetMap, rawData: data, ...queryRest }; }
内容的提问来源于stack exchange,提问作者Antuan
相关产品推荐
相关产品推荐

