GraphQL执行mutation后如何更新subscription对应缓存解决更新延迟?
核心结论
优先选择直接更新subscription对应的Apollo缓存,不需要自行维护独立的本地状态。自己维护本地状态很容易出现和服务端、缓存数据不同步的问题,而Apollo的update回调就是专门为了解决mutation后即时更新UI的场景设计的,成本更低、一致性更好。
具体实现方案
你只需要在mutation的update回调中,读取缓存中订阅的帖子列表数据,修改对应帖子的点赞数后写回缓存即可,UI会即时刷新,不需要等待subscription的推送更新。
代码示例
function LikeButton({ postId, ownLiked }) { const [insertLike, { loading: likeLoading }] = useMutation(INSERT_LIKE); const [deleteLike, { loading: unLikeLoading }] = useMutation(DELETE_LIKE); function likePost() { insertLike({ variables: { object: { user_id: owner, post_id: postId, }, }, update: (cache) => { // 1. 读取缓存中的订阅数据,query必须和你的subscription定义完全一致 const cacheData = cache.readQuery({ query: GET_POSTS_WITH_OUT_USER }); // 2. 找到对应帖子,更新点赞数 const updatedPosts = cacheData.posts.map(post => { if (post.id === postId) { return { ...post, likedCount: { ...post.likedCount, aggregate: { ...post.likedCount.aggregate, count: post.likedCount.aggregate.count + 1 } }, // 如果你在subscription中加了当前用户是否点赞的字段,这里顺便更新 // isLiked: true }; } return post; }); // 3. 把修改后的数据写回缓存 cache.writeQuery({ query: GET_POSTS_WITH_OUT_USER, data: { posts: updatedPosts } }); } }) } // 取消点赞的逻辑同理,update中把count减1即可 function unlikePost() { deleteLike({ variables: { post_id: postId, user_id: owner }, update: (cache) => { const cacheData = cache.readQuery({ query: GET_POSTS_WITH_OUT_USER }); const updatedPosts = cacheData.posts.map(post => { if (post.id === postId) { return { ...post, likedCount: { ...post.likedCount, aggregate: { ...post.likedCount.aggregate, count: post.likedCount.aggregate.count - 1 } }, // isLiked: false }; } return post; }); cache.writeQuery({ query: GET_POSTS_WITH_OUT_USER, data: { posts: updatedPosts } }); } }) } return ( <button onClick={ownLiked ? unlikePost : likePost} disabled={likeLoading || unLikeLoading} className={likeLoading || unLikeLoading ? 'cursor-not-allowed' : ''} > Like </button> ) }
注意事项
- 读取和写入缓存时使用的
GET_POSTS_WITH_OUT_USER必须和你上层subscription使用的查询完全一致,包括字段、参数、别名,否则会出现读不到缓存或者更新不生效的问题。 - 如果需要展示当前用户是否已点赞,需要先在subscription的posts查询中添加对应字段,比如用exists语法判断当前用户是否在点赞列表中,更新缓存时同步修改这个字段即可。
- 后续subscription推送最新数据时会自动覆盖你修改的缓存,不需要担心数据和服务端不一致的问题。
内容的提问来源于stack exchange,提问作者Subhendu Kundu
相关产品推荐
相关产品推荐

