Apollo Client调用resetStore后缓存未重置,skip条件失效求助
问题分析
你遇到的问题核心在于**client.resetStore()的执行时机与React组件卸载的异步性冲突**:
- 第二次点击按钮时,代码先执行
client.resetStore(),再调用setBool切换状态。 - React的状态更新是异步批量处理的,此时
Test组件还未被卸载,bool仍为true,useQuery的skip参数还是false。 resetStore()会强制重新执行所有当前活跃的查询,因此触发了不必要的网络请求。
解决方案
方案1:调整执行顺序,先卸载组件再清空缓存
利用useEffect监听bool的变化,当bool从true变为false时,再执行resetStore():
修改App.jsx:
import { useState, useEffect } from "react"; import "./App.css"; import { Test } from "../test"; import { useApolloClient } from "@apollo/client"; export default function App() { const [bool, setBool] = useState(false); const client = useApolloClient(); useEffect(() => { // 当bool变为false时,组件已卸载,再清空缓存 if (!bool) { client.resetStore(); } }, [bool, client]); return ( <main> <button onClick={() => { setBool((prev) => !prev); }} > Click me </button> {bool && <Test bool={bool} />} </main> ); }
方案2:移除冗余的skip参数
既然已经通过{bool && <Test />}控制组件渲染,Test组件只有在bool为true时才会挂载,因此可以直接移除useQuery中的skip参数,避免逻辑歧义:
修改test.jsx:
import { gql, useQuery } from "@apollo/client"; const testQuery = gql` query { countries { name } } `; export const Test = ({ bool }) => { const { data, loading, error } = useQuery(testQuery, { variables:{holy:"shit"} }); if (loading) return <p>Loading...</p>; if (error) return <p>Error :(</p>; return ( <div> {data.countries.map((country) => ( <div key={country.name}>{country.name}</div> ))} </div> ); };
方案3:自定义resetStore过滤规则
如果需要更精细的查询控制,可以在Apollo Client初始化时,通过onResetStore跳过指定查询:
const client = new ApolloClient({ uri: "YOUR_API_URL", cache: new InMemoryCache(), onResetStore: async () => { // 只重新执行非目标查询 return Promise.all( client.cache.watchQuery() .filter(query => query.query !== testQuery) .map(query => query.refetch()) ); } });
验证效果
调整后,第二次点击按钮时,bool先变为false,Test组件被卸载,之后再执行resetStore(),此时该查询已不再活跃,不会触发不必要的网络请求。
内容的提问来源于stack exchange,提问作者suyog
相关产品推荐
相关产品推荐

