案例 1:Payload 使用通用实体
简单地说,Apollo 客户端的缓存会保留从查询和突变接收到的所有内容,尽管架构需要包含 id: ID! 字段,并且任何查询都需要使用相关节点上的 id 和 __typename 字段客户端知道要更新缓存的哪一部分。
这假设突变有效负载是模式中的常见数据,可以通过正常查询检索。这是最好的情况。
给定服务器上的以下架构:
type User {
id: ID!
phoneNumber: String!
}
type Query {
user(id: String!): User!
}
type UpdateUserPayload {
user: User!
}
type Mutation {
updateUser(id: String!, phoneNumber: String!): UpdateUserPayload!
}
假设cache is used on the client:
import { InMemoryCache, ApolloClient } from '@apollo/client';
const client = new ApolloClient({
// ...other arguments...
cache: new InMemoryCache(options)
});
-
响应中包含的每个可识别对象的缓存 generates a unique ID。
-
缓存按 ID 将对象存储在平面查找表中。
-
只要传入的对象与现有对象使用相同的 ID 存储,这些对象的字段就会合并。
- 如果传入对象和现有对象共享任何字段,则传入对象覆盖这些字段的缓存值。
-
仅现有对象或仅传入对象中出现的字段被保留。
规范化在您的数据图上构建数据图的部分副本
客户端,采用针对读取和更新而优化的格式
当您的应用程序更改状态时生成图表。
客户端的变异应该是
mutation UpdateUserPhone($phoneNumber: String!, $id: String!) {
updateUser(id: $id, phoneNumber: $phoneNumber) {
user {
__typename # Added by default by the Apollo client
id # Required to identify the user in the cache
phoneNumber # Field that'll be updated in the cache
}
}
}
然后,在应用程序中通过同一个 Apollo 客户端使用该用户的任何组件都将自动更新。没什么特别的,客户端默认使用缓存,数据变化时触发渲染。
import { gql, useQuery } from '@apollo/client';
const USER_QUERY = gql`
query GetUser($id: String!) {
user(id: $id) {
__typename
id
phoneNumber
}
}
`;
const UserComponent = ({ userId }) => {
const { loading, error, data } = useQuery(USER_QUERY, {
variables: { id: userId },
});
if (loading) return null;
if (error) return `Error! ${error}`;
return <div>{data.user.phoneNumber}</div>;
}
fetchPolicy option 默认为 cache-first。
案例 2:有效负载是特定于突变的自定义数据
如果数据实际上在架构中的其他地方不可用,则无法如上所述自动使用 Apollo 缓存。
使用其他状态管理解决方案
几个选项:
这是一个使用localStorage 的example from the Apollo GraphQL documentation:
const [login, { loading, error }] = useMutation(LOGIN_USER, {
onCompleted({ login }) {
localStorage.setItem('token', login.token);
localStorage.setItem('userId', login.id);
}
});
这是一个纯粹的 Apollo GraphQL 解决方案,因为客户端也是一个状态管理库,它支持有用的开发人员工具并有助于推理数据。
-
创建本地架构。
// schema.js
export const typeDefs = gql`
type DataToKeep {
# anything here
}
extend type Query {
dataToKeep: DataToKeep # probably nullable?
}
`;
-
初始化自定义缓存
// cache.js
export const dataToKeepVar = makeVar(null);
export const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
dataToKeep: {
read() {
return dataToKeepVar();
}
},
}
}
}
});
-
在客户端初始化时应用架构覆盖
import { InMemoryCache, Reference, makeVar } from '@apollo/client';
import { cache } from './cache';
import { typeDefs } from './schema';
const client = new ApolloClient({
cache,
typeDefs,
// other options like, headers, uri, etc.
});
-
跟踪突变中的变化:
const [myMutation, { data, errors, loading }] = useMutation(MY_MUTATION, {
onCompleted({ myMutation }) {
if (myMutation && myMutation.dataToKeep)
dataToKeepVar(myMutation.dataToKeep);
}
});
-
然后,查询@client 字段。
import { gql, useQuery } from '@apollo/client';
const DATA_QUERY = gql`
query dataToKeep {
dataToKeep @client {
# anything here
}
}
`;
const AnyComponent = ({ userId }) => {
const { loading, error, data } = useQuery(DATA_QUERY);
if (loading) return null;
if (error) return `Error! ${error}`;
return <div>{JSON.stringify(data.dataToKeep)}</div>;
}
另请参阅managing local state 上的文档。