React-apollo update vs refetch

2020-03-06 13:55发布

问题:

I am using react-apollo and have been for quite some time. One thing that has already been a problem for me is the fact that refetch doesn't work when using a mutation This has been a know issue for as long as I have been using the app.

I have got round this by using the refetch prop that is available on a query.

    <Query query={query} fetchPolicy={fetchPolicy} {...props}>
      {({ loading, data, error, refetch }) => {
     ... pass down to mutation
    </Query>

However I am now reading in the documentation that you recieve an update method as part of a mutation and you should use this to update your application after a mutation.

Can you use the update function to update your UI's data and have it update after finishing a mutation? If you can, is this the standard way to do updates now?

*Using refetchQueries not working

As you can see in the image the console.info() displays that the data.status = "CREATED"; but the request coming back from the mutation directly is data.status = "PICKED"; PICKED is the correct and uptodate information in the DB.

回答1:

In order of preference, your options are:

  1. Do nothing. For regular updates to an individual node, as long as the mutation returns the mutated result, Apollo will update the cache automatically for you. When this fails to work as expected, it's usually because the query is missing the id (or _id) field. When an id field is not available, a custom dataIdFromObject function should be provided to the InMemoryCache constructor. Automatic cache updates also fail when people set the addTypename option to false.

  2. Use update. The update function will run after your mutation completes, and lets you manipulate the cache directly. This is necessary if the mutation affects a field returning a list of nodes. Unlike simple updates, Apollo has no way to infer whether the list should be updated (and how) following the mutation, so we have to directly update the cache ourselves. This is typically necessary following create and delete mutations, but may also be needed after an update mutation if the updated node should be added or removed to some field that returns a list. The docs go into a good deal of detail explaining how to do this.

<Mutation
  mutation={ADD_TODO}
  update={(cache, { data: { addTodo } }) => {
    const { todos } = cache.readQuery({ query: GET_TODOS });
    cache.writeQuery({
      query: GET_TODOS,
      data: { todos: todos.concat([addTodo]) },
    });
  }}
>
  {(addTodo) =>(...)}
</Mutation>
  1. Use refetchQueries. Instead of updating the cache, you may also provide a refetchQueries function, which should return an array of objects representing the queries to refetch. This is generally less desirable than using update since it requires one or more additional calls to the server. However, it may be necessary if the mutation does not return enough information to correctly update the cache manually. NOTE: The returned array may also be an array of strings representing operation names, though this is not well documented.
<Mutation
  mutation={ADD_TODO}
  refetchQueries={() => [
    { query: TODOS_QUERY, variables: { foo: 'BAR' } },
  ]}
>
  {(addTodo) =>(...)}
</Mutation>
  1. Use refetch. As you already showed in your question, it's possible to use the refetch function provided by a Query component inside your Mutation component to refetch that specific query. This is fine if your Mutation component is already nested inside the Query component, but generally using refetchQueries will be a cleaner solution, particularly if multiple queries need to be refetched.

  2. Use updateQueries. This is a legacy option that's no longer well-documented, but provided similar functionality to update before update was added. It should not be used as it may be deprecated in the future.

UPDATE:

You may also set up your schema in such a way that queries can be refetched as part of your mutation. See this article for more details.