apollographql / react-apollo

:recycle: React integration for Apollo Client
https://www.apollographql.com/docs/react/
MIT License
6.85k stars 790 forks source link

Difference between client.writeQuery and optimisticResponse + update in Apollo #4014

Open roballsopp opened 4 years ago

roballsopp commented 4 years ago

If I want to implement optimistic UI in Apollo, the documented way to do it is with the update option:

client.mutate({
    mutation: createSurveyResponseMutation,
    variables,
    optimisticResponse: {
        createSurveyResponse: {
            ...variables.input,
            __typename: 'SurveyResponse',
            questionResponses: { __typename: 'ModelQuestionResponseConnection', items: [] },
        },
    },
    update: (store, { data: { createSurveyResponse } }) => {
        store.writeQuery({
            query: myQuery,
            variables: { surveyResponseId: createSurveyResponse.id },
            data: {
                getSurveyResponse: createSurveyResponse,
            },
        });
    },
});

What is the difference between doing this, and just calling client.writeQuery ahead of calling the mutation:

client.writeQuery({
    query: myQuery,
    variables: { surveyResponseId: response.id },
    data: {
        getSurveyResponse: {
            ...response,
            __typename: 'SurveyResponse',
            questionResponses: { __typename: 'ModelQuestionResponseConnection', items: [] },
        },
    },
});

client.mutate({
    mutation: createSurveyResponseMutation,
    variables,
});

I have a few specific questions about this:

  1. Will apollo automatically roll back your optimistic update if the mutation fails in the first case (update option)? Is the second case a good option if I don't want this roll back behavior?
  2. In the first case, is the store guaranteed to be up-to-date with my optimistic update immediately after the call to client.mutate(...) (e.g. is it safe to call client.mutate(...) and immediately navigate to a page that needs the store to have been updated)? Do I need to use an ObservableQuery somehow to be sure the store is updated? If not, does my second case have this advantage (is the store up-to-date immediately after client.writeQuery())? Any information on the lifecycles of either of these examples is welcome.
  3. Say I create an id for my entity on the client side, I perform the second case above, and both client.writeQuery() and client.mutate(...) succeed. Since there is already an entry in the store with the correct id by the time client.mutate(...) succeeds, will that entry be automatically updated with the server response without my needing an update function (like it does when you call a mutation to update an existing item in the store)?
  4. One advantage to the second case is you avoid having to write extra code to handle the update function being called twice (once for your optimistic response and again for the server response), which you need to do when you are appending some or all of the response to a list in the store. Are there any downsides to the second case? Why wouldn't I just always do this?