Using both optimistic mutation results and update functions

I have a question about how optimistic updates from mutations work with the onQueryUpdated callback.

I have a query that gets a list of items, and a mutation that creates a new item that belongs in that list. The mutation returns the new item in its response.
Using the update callback I’m able to modify the cache directly to add the new item to the list. When the mutation response is received, my update callback is called, the cache is modified, then the onQueryUpdated callback is called, the original query is updated, and the new value is displayed. This works exactly as I’d expect.

However, if I specify an optimistic response from the mutation the update callback is now called twice (as I’d expect, once immediately based on the optimistic response, and a second time asynchronously when the actual response is received) but the onQueryUpdated callback is still only called once, after the actual response is received. This means that the new item is still not displayed in the list until after the actual response is received, whereas I would expect it to be rendered immediately based on the optimistic response.

Is this the expected behavior? If so, is there a recommended pattern for optimistically adding an item to a list to maintain a “live” UX?

Thanks

it can be optimized further to provide the desired “live” UX you’re looking for. In this case, you’ll want to manually update the cache to reflect the optimistic response immediately, while still allowing for the actual server response to update the cache again later.

Here’s a pattern for optimistically adding an item to a list using Apollo Client:

  1. Write your mutation with the optimisticResponse option:
const [createItem] = useMutation(CREATE_ITEM_MUTATION, {
  optimisticResponse: {
    __typename: "Mutation",
    createItem: {
      __typename: "Item",
      id: "temp-id", // Use a temporary ID or a unique identifier
      // Add other required fields for the item with default or temporary values
    },
  },
  update: (cache, { data: { createItem } }) => {
    const query = GET_ITEMS_QUERY;
    const data = cache.readQuery({ query });

    cache.writeQuery({
      query,
      data: {
        ...data,
        items: [...data.items, createItem],
      },
    });
  },
});

  1. Use the onQueryUpdated callback if you need to perform additional actions after the cache is updated. Note that this callback will still only be called once, after the actual response is received.