Search code examples
javascripttypescriptgraphqlapollo

Apollo optimisticResponse not applied when query is pending


If you have a pending query when a mutation with an optimisticResponse is executed, the optimisticResponse doesn’t get applied.

const {data, refetch} = useQuery(GET_TODOS);
const [updateTodo] = useMutation(UPDATE_TODO);

// in a form submit handler:
refetch();

// Immediately mutate while the _query_ is pending
updateTodo({
  variables: { id, description: description + 1},
  optimisticResponse: {
     updateTodo: {
        id,
        __typename: "Todo",
        description: description + 1
     }
  }
});

Minimal codesandbox.io example. There’s an artificial 1 second delay link added to make the effect more obvious.

The same behaviour appears to occur with direct cache writes as well; writes will not cause a re-render if there is a pending read query. The same behaviour can also be witnessed if batching a query in with a mutation.

Is this the intended behaviour? And if so, is there a way to bypass it?


Solution

  • The Apollo useQuery hook uses a default fetch-policy of cache-first. Internally when the Apollo cache is updated the following occurs

    1. Check if any queries are observing that part of the cache
    2. Check if they should be notified of the update
    3. Notify

    When checking whether to notify a query, there is a check to see if the query is currently in flight to the server and if so only notify when the fetch-policy is cache-only or cache-and-network.

    This is fine, and makes sense, you don't want to spend CPU re-rendering when you know the data is just about to update.

    This causes a problem in the example above due to the refetch query being in progress when the optimistic update is applied. The shouldNotify check will return false. Changing the queries fetch policy fixes this

    const {data, refetch} = useQuery(GET_TODOS, {
       fetchPolicy: 'cache-and-network'
    });