如何从Apollo缓存获取更新数据?Apollo Client是否有类似mapStateToProps的机制?
mapStateToProps 的功能,你的问题出在手动读取缓存的方式上 首先,你现在的写法里,this.props.client.readFragment 只是在组件渲染时一次性读取缓存数据,并没有让 Apollo Client 把这个组件和缓存数据建立「订阅关系」——所以当兄弟组件通过 writeFragment 更新缓存后,你的 Container 组件根本不知道数据变了,自然不会重新渲染,Child 的 props 也就不会更新。
Apollo Client 提供的「自动跟踪缓存变化并更新组件」的机制,其实就是类似 Redux mapStateToProps 的功能,下面给你两种解决思路,对应类组件和函数组件的场景:
1. 类组件:用 graphql 高阶组件注入数据
如果你还在使用类组件,推荐用 Apollo 的 graphql HOC 把片段数据作为查询的一部分注入到组件 props 里,这样 Apollo 会自动跟踪缓存中这个片段的变化,一旦缓存更新,组件就会重新渲染。
示例代码:
import { graphql } from '@apollo/client/react/hoc'; import gql from 'graphql-tag'; const NOTES_QUERY = gql` query GetNotes { # 这里要对应你片段关联的根查询字段,比如假设你的 NOTES_FRAGMENT 是针对 Note 列表的 notes { ...NotesFragment } } ${NOTES_FRAGMENT} `; class Container extends React.Component { render() { // 现在 notes 会从 props 里获取,而且缓存更新时会自动更新 const { notes } = this.props.data; return <Child notes={notes} />; } } // 用 graphql HOC 包裹组件,注入查询数据 export default graphql(NOTES_QUERY)(Container);
2. 函数组件:用 useFragment 或 useQuery 钩子
如果是函数组件,更推荐用 Apollo 提供的 useFragment 钩子,它专门用来读取片段数据,并且会自动订阅缓存变化:
import { useFragment } from '@apollo/client'; function Container() { // 传入片段对应的缓存对象引用(比如从父组件传递的 ref,或通过查询获取的缓存标识) const { loading, data } = useFragment( NOTES_FRAGMENT, cache.identify('NotesList') // 假设你的列表缓存有对应的唯一标识 ); if (loading) return <div>Loading...</div>; return <Child notes={data.notes} />; }
另外,也可以直接用 useQuery 来查询包含片段的字段,效果和类组件的 HOC 类似,Apollo 会自动处理缓存订阅。
补充:确保你的 update 函数逻辑正确
还要检查兄弟组件里的 update 函数,确保 writeFragment 时传入的 data 是正确更新后的列表,比如:
update={(cache, { data: { updateNote } }) => { const { notes } = cache.readFragment({ fragment: NOTES_FRAGMENT, id: 'NotesList', // 匹配你缓存中列表的唯一标识 }); // 找到要更新的 note 并替换 const updatedNotes = notes.map(note => note.id === updateNote.id ? updateNote : note ); // 写入更新后的列表 cache.writeFragment({ fragment: NOTES_FRAGMENT, id: 'NotesList', data: { notes: updatedNotes }, }); }}
总结
Apollo Client 的查询钩子(useQuery/useFragment)和 graphql 高阶组件,本质上就相当于 Redux 的 mapStateToProps + 自动订阅状态变化——它们会把缓存中的数据映射到组件 props,并且在缓存更新时自动触发组件重渲染,完全不需要你手动调用 readFragment。
内容的提问来源于stack exchange,提问作者Yichz

