查询后如何更新 Apollo 缓存?
Posted
技术标签:
【中文标题】查询后如何更新 Apollo 缓存?【英文标题】:How to update Apollo cache after query? 【发布时间】:2020-05-11 13:52:02 【问题描述】:如何覆盖 Apollo 缓存中的值?
我有一个 graphql 查询来获取用户。这将返回具有默认货币的用户。然后可以从选择下拉列表中覆盖该货币。
查询从 API 获取 paymentCurrencies
,然后使用客户端解析器将 paymentCurrencies
数组中的第一项设置为用户 currency
query me
me
username
currency @client
paymentCurrencies
当有人从下拉菜单中选择一种货币时,我想用他们选择的任何货币覆盖用户的货币。
到目前为止,我有这样的事情:
const onChange = e =>
const value = e.target
client.writeData( user: currency: value, username, __typename: "User" )
我收到以下错误:Error writing result to store for query:
"kind":"Document","definitions":["kind":"OperationDefinition","operation":"query","name":"kind":"Name","value":"GeneratedClientQuery","selectionSet":null]
Cannot read property 'selections' of null
使用writeData
是正确的方法还是应该使用writeQuery
之类的?
【问题讨论】:
【参考方案1】:如另一个答案中所述,您可能需要一个简单的查询和变异设置。 client 指令用于扩展您的模式以保存仅限客户端的附加数据。根据您的解释,听起来您明确希望将此数据与服务器同步。
const ME_QUERY = gql`
query me
me
username
currency
paymentCurrencies
`;
const CURRENCY_MUTATION = gql`
mutation setCurrency($currency: String)
setCurrency(currency: $currency)
me
username
currency
`;
function MyComponent()
const data = useQuery(ME_QUERY);
const [setCurrency] = useMutation(CURRENCY_MUTATION);
const onChange = e => setCurrency(
variables: currency: e.currentTarget.value ,
);
return (
<>
<h2>data && data.me.currency</h2>
<select onChange=onChange>
/* your dropdown logic */
</select>
</>
);
你明白了。 Apollo 现在将自动更新您的缓存。确保您的变异允许查询更新的用户对象。
为了使自动更新工作您的用户需要被缓存识别。您可以通过添加一个 id 字段并在查询和突变中选择它,或者在 Apollo Client 2.x 中实现一个 dataIdFromObject
函数,其中包括 __typename === 'User'
的用户名,或者在 Apollo Client 中使用类型策略来做到这一点3.x。找到docs here。
【讨论】:
那么 setCurrency 会是客户端解析器突变吗?我仍然需要将货币写入缓存的解析器中的逻辑,但不是吗?【参考方案2】:writeData
应该用于更改根的字段,例如:
yourState @client
在这种情况下,您应该使用 writeQuery。此外,这个逻辑真的应该被提取到一个(本地)突变中,然后您可以在组件内部调用。使用writeQuery
时,基本思路是抓取已有数据,进行复制,然后根据需要进行转换:
const me = client.readQuery( query: ME_QUERY )
const data =
me:
...me,
currency: value,
client.writeQuery( query: ME_QUERY, data )
您也可以使用writeFragment
直接修改缓存中对象的单个实例。但是,您需要对象的缓存键。因为缓存键派生自 __typename
和 id
字段,所以您应该确保查询首先包含 id 字段。无论确保您的缓存可以轻松更新,这是一个很好的做法(有关更多详细信息,请参阅here)。然后你可以这样做:
client.writeFragment(
id: 'User:42',
fragment: gql`
fragment UserCurrency on User
currency @client
`,
data:
currency: value,
,
)
【讨论】:
【参考方案3】:视情况而定。
对于持久更改(同步到服务器),您应该只使用突变更改用户设置。
对于会话感知更改 - 不要使用用户设置 - 将此(从记录的用户属性)复制到全局应用状态(redux/mobx 或在本例中为 apollo local state 的 separate 值) )。
在这两种情况下,使用更改的数据更新许多组件可能会出现罕见的问题。
Redux/mobx 自动解决了这个问题。
Apollo HOC 不会重新渲染。
钩子 - 部分更新(仅具有 useQuery
和 useMutation
对的一个),其他将仅在重新渲染时更新。
使用 <Query/>
构建的组件会在内部创建一个 observable,然后它们也会被更新。
Mutation 有update
和refetchQueries
参数。
还有一个package 用于更复杂的用例。
【讨论】:
以上是关于查询后如何更新 Apollo 缓存?的主要内容,如果未能解决你的问题,请参考以下文章
如何从突变查询中更新 Apollo 数据存储/缓存,更新选项似乎没有触发