Apollo Cache无参字段重定向:如何匹配登录获取的用户对象
无需硬编码ID的缓存重定向实现方案
你的问题本质是缺少一个可长期追踪的「当前登录用户缓存指针」,不需要硬编码ID,也不需要给GetUser新增入参,完全可以通过Apollo内置的缓存读写能力实现自动指向登录返回的用户对象。
实现步骤
1. 登录成功时写入当前用户指针
在login mutation的成功回调中,除了把JWT存在本地,手动往Apollo缓存里写一个专门的字段,用来存当前登录用户的账户ID——这个字段纯本地存储,不需要后端接口支持。
示例代码:
const [login] = useMutation(LOGIN_MUTATION, { onCompleted: (loginResponse) => { // 常规存储JWT localStorage.setItem('auth_jwt', loginResponse.login.jwt) // 把当前登录用户ID写入缓存的专用字段 client.cache.writeQuery({ query: gql`query CurrentUserPointer { currentLoggedInAccountId }`, data: { currentLoggedInAccountId: loginResponse.login.user.account.id } }) } })
这里不需要担心缓存匹配的问题,因为你已经给User类型配置了keyFields: ["account", ["id"]]的规则,登录返回的用户对象会自动按照这个规则写入缓存,对应的缓存键就是User:登录返回的账户ID,后续通过引用查找时可以直接命中。
2. 替换类型策略里的硬编码重定向
把之前写死账户ID的user字段重定向逻辑,改成从缓存读取刚才存的用户指针,动态生成用户引用:
const typePolicies: TypePolicies = { User: { // 适配当前类型结构,不需要调整 keyFields: ["account", ["id"]], }, Query: { fields: { // 给纯本地的用户指针字段配置读取规则,不需要后端返回 currentLoggedInAccountId: { read(cachedValue) { return cachedValue ?? null } }, user(_, { toReference, readField }) { // 从缓存读取当前登录用户的账户ID const currentAccountId = readField('currentLoggedInAccountId') // 未登录场景直接返回空 if (!currentAccountId) return null // 动态生成对应用户实体的缓存引用,完全不需要硬编码ID return toReference({ __typename: "User", account: { id: currentAccountId } }) }, }, }, }
为什么不建议给GetUser加id入参
- 你的后端本身是靠请求携带的JWT识别用户身份,前端额外传id入参属于完全冗余的逻辑,甚至会带来越权风险(比如前端篡改id去拉取其他用户的数据)
- 加了入参之后,Apollo会把不同id的请求识别为不同的缓存键,后续切换登录账号、登出场景都需要手动清理多版本的缓存,维护成本比纯指针方案高很多
- 无参查询本身是和后端的身份校验逻辑匹配的,改造后反而打破了前后端的职责边界,还需要在全局登录状态同步时额外给所有GetUser调用位置传入最新的id值,多了很多不必要的样板代码
配套的登出清理逻辑
登出场景只要把缓存里的用户指针清空就行,重定向逻辑会自动返回空值,不会残留上一个登录用户的缓存数据:
const handleLogout = () => { localStorage.removeItem('auth_jwt') client.cache.writeQuery({ query: gql`query CurrentUserPointer { currentLoggedInAccountId }`, data: { currentLoggedInAccountId: null } }) }
实现后的实际效果
- 只要登录完成,所有调用无参
user字段的查询,都会优先读取缓存中对应ID的用户数据,不会触发网络请求 - 如果缓存中没有对应用户的实体(比如用户清了浏览器缓存、首次进入应用),Apollo会自动发起网络请求拉取用户数据,拉取完成后会按照之前的keyFields规则自动写入缓存
- 整个链路完全基于实际登录返回的用户ID做指向,没有任何硬编码值
内容的提问来源于stack exchange,提问作者Peterhack
相关产品推荐
相关产品推荐

