useMutation配置refetchQueries时关联useQuery的onCompleted不触发如何解决?
问题原因
Apollo Client的useQuery的onCompleted回调默认仅在首次主动查询成功完成时触发,通过refetchQueries、refetch方法触发的重取操作、缓存更新触发的查询数据更新,都不会触发该回调,这是官方的预设行为。
另外你当前refetchQueries仅传查询名称字符串的写法也可能存在匹配问题:如果对应useQuery的变量和重取时传入的变量不一致,Apollo Client会创建新的查询实例,不会关联到你已经声明的那个useQuery,自然也不会触发对应回调。
解决方案
- 方案1:将逻辑迁移到
useEffect监听数据变化
把原本写在onCompleted里的逻辑,改为监听useQuery返回的data和loading状态,只要数据更新就执行对应逻辑:
let { loading, data } = useQuery( gql` ${templateFragment} query getUserData($userToken: String) { getUsersData(userToken: $userToken) { templates { ...template } token } } `, { variables: { userToken: userToken ? userToken.replace(/"/g, ``) : null, }, onError: () => console.log("err"), } ); useEffect(() => { // 加载结束且数据存在时执行逻辑 if (!loading && data?.getUsersData) { props.isAuthAC( true, data.getUsersData.templates, data.getUsersData.token ); } }, [loading, data, props]);
- 方案2:修改
refetchQueries写法,指定完整查询和变量,同时配置awaitRefetchQueries
如果需要在mutation完成、所有重取查询结束后执行逻辑,可以直接在mutation的回调里处理,不用依赖useQuery的onCompleted:
首先把你的查询单独抽出来复用:
// 单独抽离gql查询定义方便复用 const GET_USER_DATA = gql` ${templateFragment} query getUserData($userToken: String) { getUsersData(userToken: $userToken) { templates { ...template } token } } `
修改useMutation配置:
let [saveTemplate, { loading}] = useMutation(gql` ${templateFragment} mutation saveTemplate ($template:saveTemplateTemplatesType!,$token:String!){ saveTemplate(template:$template,token:$token){ ...template } } `,{ refetchQueries: [ { query: GET_USER_DATA, // 传入和useQuery完全一致的变量 variables: { userToken: userToken ? userToken.replace(/"/g, ``) : null } } ], // 等待所有重取查询完成后再触发onCompleted awaitRefetchQueries: true, onError:()=>{message.warn("error")}, onCompleted:()=>{ console.log("success") // 这里可以直接从缓存读取最新数据执行逻辑,也可以通过client.readQuery读取最新的getUserData数据 } });
- 方案3:直接通过mutation返回结果更新缓存(最优性能)
如果mutation返回的结果已经包含了更新后的模板数据,你可以直接在onCompleted里手动更新Apollo缓存里的getUserData数据,不需要额外发起重取请求,性能更好。
内容的提问来源于stack exchange,提问作者derty14
相关产品推荐
相关产品推荐

