Apollo Client调用Add接口时refetchQueries重复触发两次问题求解
Apollo Client Mutation中refetchQueries重复执行解决方案
触发原因
该问题在搭配graphql@15.5.0使用旧版Apollo Client时非常常见,核心触发原因包括三个:
- refetchQueries配置直接写在useMutation入参中,组件重渲染时配置引用更新导致重复注册触发
- refetchQueries内的variables每次渲染生成新对象,引用不稳定被Apollo识别为不同查询
- 页面内存在多个相同Query的useQuery订阅,refetchQueries默认触发所有匹配查询的重拉
可行解决方案
方案1:将refetchQueries移入mutation触发参数
不要把refetchQueries写在useMutation的初始化配置里,改为调用mutation方法时动态传入,避免重渲染导致的重复注册:
const [Add, { loading: applyLoad }] = useMutation(APPLY, { onCompleted(data) { // 原有业务逻辑 }, onError(error) { message.error(error.message); }, awaitRefetchQueries: true, }); // 触发新增操作的函数 const handleSubmit = async (formData) => { await Add({ variables: formData, refetchQueries: [ { query: ACTIVITIES_Y, variables: { sortBy: 'date' }, }, { query: ACTIVITIES_X, variables: { sortBy: 'date' }, }, ] }) }
方案2:稳定refetchQueries的引用
如果需要保留useMutation内的refetchQueries配置,用useMemo包裹配置项避免引用频繁更新:
import { useMemo } from 'react' // 稳定refetchQueries的引用 const refetchQueries = useMemo(() => [ { query: ACTIVITIES_Y, variables: { sortBy: 'date' }, }, { query: ACTIVITIES_X, variables: { sortBy: 'date' }, }, ], []) const [Add, { loading: applyLoad }] = useMutation(APPLY, { onCompleted(data) { // 原有业务逻辑 }, onError(error) { message.error(error.message); }, awaitRefetchQueries: true, refetchQueries });
方案3:用update手动更新缓存(最优解)
完全放弃refetchQueries,通过mutation的update方法直接修改Apollo缓存,既不会产生额外请求,也完全避免重复触发问题,性能更好:
const [Add, { loading: applyLoad }] = useMutation(APPLY, { onCompleted(data) { // 原有业务逻辑 }, onError(error) { message.error(error.message); }, update(cache, { data: addResult }) { // 读取ACTIVITIES_Y的现有缓存 const yData = cache.readQuery({ query: ACTIVITIES_Y, variables: { sortBy: 'date' } }) // 更新后写入缓存 cache.writeQuery({ query: ACTIVITIES_Y, variables: { sortBy: 'date' }, data: { activitiesY: [...yData.activitiesY, addResult.newActivity] } }) // 同理更新ACTIVITIES_X的缓存 const xData = cache.readQuery({ query: ACTIVITIES_X, variables: { sortBy: 'date' } }) cache.writeQuery({ query: ACTIVITIES_X, variables: { sortBy: 'date' }, data: { activitiesX: [...xData.activitiesX, addResult.newActivity] } }) } });
临时兼容方案
如果不想改动现有逻辑,可以在useMutation配置中新增notifyOnNetworkStatusChange: false,该配置可以解决旧版本Apollo Client的重复触发bug:
const [Add, { loading: applyLoad }] = useMutation(APPLY, { onCompleted(data) { // 原有业务逻辑 }, onError(error) { message.error(error.message); }, awaitRefetchQueries: true, notifyOnNetworkStatusChange: false, // 新增该行 refetchQueries: [ { query: ACTIVITIES_Y, variables: { sortBy: 'date' }, }, { query: ACTIVITIES_X, variables: { sortBy: 'date' }, }, ], });
内容的提问来源于stack exchange,提问作者VIKASH GUPTA
相关产品推荐
相关产品推荐

