Apollo for GraphQL执行Mutation后未返回更新数据问题
解决Apollo Client Mutation后缓存未更新导致组件显示Loading的问题
看起来你遇到的是Apollo Client缓存更新的典型问题——虽然新歌词已经成功写入MongoDB,但Apollo并没有自动更新缓存中对应song对象的lyrics数组,导致你的SongDetail组件无法获取到更新后的song数据,只能显示loading。刷新页面后重新从服务器拉取数据,自然就正常了。
下面给你两种实用的解决方案,你可以根据自己的需求选择:
方案一:手动更新缓存(性能更优)
这种方式不需要重新请求服务器,直接修改Apollo缓存中的数据,是推荐的做法。你需要在LyricCreate组件的Mutation配置中添加update函数,手动把新增的歌词添加到对应song的lyrics数组里。
首先,假设你的添加歌词的Mutation定义如下(如果和你的实际代码有出入,调整成你自己的即可):
const addLyricToSong = gql` mutation addLyricToSong($songId: ID!, $content: String!) { addLyricToSong(songId: $songId, content: $content) { id content } } `;
然后在包装LyricCreate组件时,配置update函数:
import fetchSong from './path-to-your-fetchSong-query'; // 导入SongDetail里的fetchSong查询 export default graphql(addLyricToSong, { props: ({ mutate }) => ({ addLyric: (songId, content) => mutate({ variables: { songId, content }, update: (store, { data: { addLyricToSong } }) => { // 1. 从缓存中读取当前的song数据 const cachedSongData = store.readQuery({ query: fetchSong, variables: { id: songId } }); // 2. 将新歌词添加到lyrics数组中 cachedSongData.song.lyrics.push(addLyricToSong); // 3. 将更新后的数据写回缓存 store.writeQuery({ query: fetchSong, variables: { id: songId }, data: cachedSongData }); } }) }) })(LyricCreate);
这里的关键是:
- 用
store.readQuery读取缓存中对应id的song数据(必须和SongDetail里的查询语句完全一致,包括字段和变量) - 修改lyrics数组后,用
store.writeQuery把更新后的数据写回缓存,这样Apollo会自动通知SongDetail组件更新props,你就能看到新歌词了。
方案二:使用refetchQueries强制重新查询
如果你觉得手动操作缓存太麻烦,可以让Apollo在Mutation成功后,重新执行fetchSong查询,从服务器拉取最新的song数据。这种方式更简单,适合快速解决问题:
import fetchSong from './path-to-your-fetchSong-query'; export default graphql(addLyricToSong, { props: ({ mutate }) => ({ addLyric: (songId, content) => mutate({ variables: { songId, content }, refetchQueries: [ { query: fetchSong, variables: { id: songId } // 和SongDetail里的变量一致 } ] }) }) })(LyricCreate);
执行Mutation后,Apollo会自动重新请求fetchSong,把最新的数据更新到缓存中,SongDetail组件就能拿到包含新歌词的song对象,不会再显示loading了。
注意事项
- 确保你的Mutation返回的字段(比如
id和content)和fetchSong查询中lyrics的字段完全匹配,这样不管是手动更新缓存还是重新查询,数据结构都是一致的。 - 你已经配置了
dataIdFromObject: o => o.id,只要你的song和lyric对象都有唯一的id字段,这个配置是没问题的,Apollo能正确识别缓存中的对象。
内容的提问来源于stack exchange,提问作者Kayote
相关产品推荐
相关产品推荐

