简体   繁体   中英

Does Apollo cache the returned data from a mutation

I'm using Apollo Client in a React app and I need to do a mutation then keep the returned data for later use (but I won't have access to the variables ), do I have to use a another state management solution or can we do this in Apollo?

I've read about doing this with query but not mutation.

Here's my code so far

// 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',
        },
      },
    });
  }}

edit:

here is the mutation

export const MY_MUTATION = gql`
  mutation MyMutation($input: MyMutationInput!) {
    myMutation(input: $input) {
      dataToKeep
      expiresAt
    }
  }
`;

and the schema for this mutation

MyMutationInput:
  phoneNumber: String!
  id: String!

MyMutationPayload:
  dataToKeep
  expiresAt
  

Case 1: Payload is using common entities

Simply put, the Apollo client's cache keeps everything that's received from queries and mutations, though the schema needs to include id: ID! fields and any query needs to use both the id and __typename fields on relevant nodes for the client to know which part of the cache to update.

This assumes that the mutation payload is common data from the schema that can be retrieved through a normal query. This is the best case scenario.

Given the following schema on the server:

type User {
  id: ID!
  phoneNumber: String!
}

type Query {
  user(id: String!): User!
}

type UpdateUserPayload {
  user: User!
}

type Mutation {
  updateUser(id: String!, phoneNumber: String!): UpdateUserPayload!
}

And assuming a 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.

The client's mutation should be

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
    }
  }
}

Then, any component using this user through the same Apollo client in the app will be up to date automatically. There's nothing special to do, the client will use the cache by default and trigger renders whenever the data changes.

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>;
}

The fetchPolicy option defaults to cache-first .


Case 2: Payload is custom data specific to the mutation

If the data is in fact not available elsewhere in the schema, it won't be possible to use the Apollo cache automatically as explained above.

Use another state management solution

A couple options:

Here's an example from the Apollo GraphQL documentation using the 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

This is a pure Apollo GraphQL solution since the client is also a state management library, which enables useful developer tooling and helps reason about the data.

  1. Create a local schema.

     // schema.js export const typeDefs = gql` type DataToKeep { # anything here } extend type Query { dataToKeep: DataToKeep # probably nullable? } `;
  2. Initialize a custom cache

    // cache.js export const dataToKeepVar = makeVar(null); export const cache = new InMemoryCache({ typePolicies: { Query: { fields: { dataToKeep: { read() { return dataToKeepVar(); } }, } } } });
  3. Apply the schema override at the client's initialization

    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. Keep track of the changes in the mutation:

     const [myMutation, { data, errors, loading }] = useMutation(MY_MUTATION, { onCompleted({ myMutation }) { if (myMutation && myMutation.dataToKeep) dataToKeepVar(myMutation.dataToKeep); } });
  5. Then, query the @client field.

     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>; }

See also the documentation on managing local state .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM