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)
});
  1. The cache generates a unique ID for every identifiable object included in the response.

  2. The cache stores the objects by ID in a flat lookup table.

  3. 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 缓存。

使用其他状态管理解决方案

几个选项:

这是一个 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 解决方案,因为客户端也是一个状态管理库,启用有用的开发人员工具并帮助推理数据。

  1. 创建本地架构。

    // schema.js
    export const typeDefs = gql`
      type DataToKeep {
        # anything here
      }
    
      extend type Query {
        dataToKeep: DataToKeep # probably nullable?
      }
    `;
    
  2. 初始化自定义缓存

    // cache.js
    export const dataToKeepVar = makeVar(null);
    
    export const cache = new InMemoryCache({
      typePolicies: {
        Query: {
          fields: {
            dataToKeep: {
              read() {
                return dataToKeepVar();
              } 
            },
          }
        }
      }
    });
    
  3. 在客户端初始化时应用模式覆盖

    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.
    });
    
  4. 跟踪突变的变化:

    const [myMutation, { data, errors, loading }] = useMutation(MY_MUTATION, {
      onCompleted({ myMutation }) {
        if (myMutation && myMutation.dataToKeep)
          dataToKeepVar(myMutation.dataToKeep);
      }
    });
    
  5. 然后,查询@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 上的文档。