登出时无法清除apollo-client缓存,新用户登录后仍展示旧用户数据
问题根因
- Apollo Client 实例化时硬编码了请求头的
Authorization字段,该值仅会在实例创建时读取一次 localStorage,后续切换用户更新 localStorage 中的 token 后,请求仍然携带旧用户的 token,后端返回的旧用户数据会覆盖你手动写入缓存的新用户信息。 - 登出逻辑顺序错误,先清理缓存再清除本地身份凭证,清理缓存时触发的活跃查询自动重发仍然携带旧 token,拉取到旧用户数据。
- 冗余的缓存清理操作互相冲突:
clearStore和resetStore功能重叠,重复调用会导致预期外的缓存行为。
解决方案
1. 修正 Apollo Client 配置,使用动态请求头
移除硬编码的 headers 配置,改用 setContext 中间件在每次请求前读取最新的 token:
import { setContext } from '@apollo/client/link/context'; import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'; const httpLink = createHttpLink({ uri: config.apiUrl, }); // 每次请求前动态注入最新的授权头 const authLink = setContext((_, { headers }) => { const token = localStorage.getItem(config.localStorage); return { headers: { ...headers, Authorization: token ? `Bearer ${token}` : '', } } }); const apolloClient = new ApolloClient({ link: authLink.concat(httpLink), cache: new InMemoryCache({ // 如果你的用户表主键不是默认的`id`,需在此处指定主键字段,避免缓存把不同用户识别为同一对象 typePolicies: { User: { keyFields: ['userId'] // 替换为你实际的用户主键字段名 } } }), });
2. 修正登出逻辑,调整操作顺序
移除冗余的缓存清理调用,先清除本地身份凭证再清理缓存:
onClick={() => { // 第一步:先清除本地存储的token和全局用户状态 localStorage.removeItem(config.localStorage); dispatch(logoutUser); // 第二步:重置缓存,自动重发所有活跃查询(此时已无有效token,不会返回旧用户数据) client.resetStore() .then(() => history.push('/')); }}
3. 简化登录逻辑,无需手动写入缓存
登录成功后先存储新用户的 token,再重置缓存即可,useUserQuery 会自动携带新 token 请求最新的用户数据,无需手动调用 writeQuery:
sendLogin({ variables: login, onCompleted: (data) => { // 存储新用户的token localStorage.setItem(config.localStorage, data.login.token); // 重置缓存后活跃查询会自动拉取新用户数据 client.resetStore(); history.push('/'); } })
内容的提问来源于stack exchange,提问作者AndrogenAgonist
相关产品推荐
相关产品推荐

