Apollo 是否缓存突变返回的数据
Does Apollo cache the returned data from a mutation
我在 React 应用程序中使用 Apollo Client,我需要进行修改,然后保留返回的数据供以后使用(但我无法访问变量),我是否必须使用另一个状态管理解决方案或者我们可以在 Apollo 中执行此操作吗?
我读过有关使用查询而非突变执行此操作的信息。
到目前为止,这是我的代码
// Mutation
const [myMutation, { data, errors, loading }] = useMutation(MY_MUTATION, {
onCompleted({ myMutation }) {
console.log('myMutation: ', myMutation.dataToKeep);
if (myMutation && myMutation.dataToKeep)
SetResponse(myMutation.dataToKeep);
},
onError(error) {
console.error('error: ', error);
},
});
//How I call it
onClick={() => {
myMutation({
variables: {
input: {
phoneNumber: '0000000000',
id: '0000',
},
},
});
}}
编辑:
这里是突变
export const MY_MUTATION = gql`
mutation MyMutation($input: MyMutationInput!) {
myMutation(input: $input) {
dataToKeep
expiresAt
}
}
`;
以及此变更的模式
MyMutationInput:
phoneNumber: String!
id: String!
MyMutationPayload:
dataToKeep
expiresAt
案例 1:负载使用普通实体
简而言之,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)
});
The cache generates a unique ID for every identifiable object included in the response.
The cache stores the objects by ID in a flat lookup table.
Whenever an incoming object is stored with the same ID as an existing object, the fields of those objects are merged.
- If the incoming object and the existing object share any fields, the incoming object overwrites the cached values for those fields.
- Fields that appear in only the existing object or only the incoming object are preserved.
Normalization constructs a partial copy of your data graph on your
client, in a format that's optimized for reading and updating the
graph as your application changes state.
客户的变异应该是
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 缓存。
使用其他状态管理解决方案
几个选项:
- 本地存储
- React's context API
- 等等
这是一个 example from the Apollo GraphQL documentation 使用 localStorage
:
const [login, { loading, error }] = useMutation(LOGIN_USER, {
onCompleted({ login }) {
localStorage.setItem('token', login.token);
localStorage.setItem('userId', login.id);
}
});
Define a client-side schema
这是一个纯粹的 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 上的文档。
我在 React 应用程序中使用 Apollo Client,我需要进行修改,然后保留返回的数据供以后使用(但我无法访问变量),我是否必须使用另一个状态管理解决方案或者我们可以在 Apollo 中执行此操作吗?
我读过有关使用查询而非突变执行此操作的信息。
到目前为止,这是我的代码
// Mutation
const [myMutation, { data, errors, loading }] = useMutation(MY_MUTATION, {
onCompleted({ myMutation }) {
console.log('myMutation: ', myMutation.dataToKeep);
if (myMutation && myMutation.dataToKeep)
SetResponse(myMutation.dataToKeep);
},
onError(error) {
console.error('error: ', error);
},
});
//How I call it
onClick={() => {
myMutation({
variables: {
input: {
phoneNumber: '0000000000',
id: '0000',
},
},
});
}}
编辑:
这里是突变
export const MY_MUTATION = gql`
mutation MyMutation($input: MyMutationInput!) {
myMutation(input: $input) {
dataToKeep
expiresAt
}
}
`;
以及此变更的模式
MyMutationInput:
phoneNumber: String!
id: String!
MyMutationPayload:
dataToKeep
expiresAt
案例 1:负载使用普通实体
简而言之,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)
});
The cache generates a unique ID for every identifiable object included in the response.
The cache stores the objects by ID in a flat lookup table.
Whenever an incoming object is stored with the same ID as an existing object, the fields of those objects are merged.
- If the incoming object and the existing object share any fields, the incoming object overwrites the cached values for those fields.
- Fields that appear in only the existing object or only the incoming object are preserved.
Normalization constructs a partial copy of your data graph on your client, in a format that's optimized for reading and updating the graph as your application changes state.
客户的变异应该是
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 缓存。
使用其他状态管理解决方案
几个选项:
- 本地存储
- React's context API
- 等等
这是一个 example from the Apollo GraphQL documentation 使用 localStorage
:
const [login, { loading, error }] = useMutation(LOGIN_USER, {
onCompleted({ login }) {
localStorage.setItem('token', login.token);
localStorage.setItem('userId', login.id);
}
});
Define a client-side schema
这是一个纯粹的 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 上的文档。