Conditionally execute a graphql mutation after a query is fetched

1.1k views Asked by At

Scenario

When a user is authenticated (isAuthenticated booelan ref):

  1. Check if a user has preferences by a graphql call to the backend (useViewerQuery)
  2. If there are no preferences for the user set the default (useSetPreferenceDefaultMutation)

Problem

Both the query and the mutation work correctly in the graphql Playground and in the Vue app. They have been generated with the graphql codegenerator which uses useQuery and useMutation in the background.

The issue we're having is that we can't define the correct order. Sometimes useSetPreferenceDefaultMutation is executed before useViewerQuery. This resets the user's settings to the defaults and it not the desired behavior.

Also, on a page refresh all is working correctly. However, when closing an reopening the page it always calls useSetPreferenceDefaultMutation.

Code

export default defineComponent({
  setup() {
    const {
      result: queryResult,
      loading: queryLoading,
      error: queryError,
    } = useViewerQuery(() => ({
      enabled: isAuthenticated.value,
    }))

    const {
      mutate: setDefaultPreferences,
      loading: mutationLoading,
      error: mutationError,
      called: mutationCalled,
    } = useSetPreferenceDefaultMutation({
      variables: {
        language: 'en-us',
        darkMode: false,
      },
    })

    onMounted(() => {
      watchEffect(() => {
        if (
          isAuthenticated.value &&
          !queryLoading.value &&
          !queryResult.value?.viewer?.preference &&
          !mutationCalled.value
        ) {
          void setDefaultPreferences()
        }
      })
    })

    return {
      isAuthenticated,
      loading: queryLoading || mutationLoading,
      error: queryError || mutationError,
    }
  },
})

Failed efforts

  • We opened an issue here and here to have extra options on useQuery or useMutation which could help in our scenario but no luck.
  • Use fetch option with sync or post on watchEffect
  • Use watch instead of watchEffect
1

There are 1 answers

0
DarkLite1 On BEST ANSWER

Thanks to comment from @xadm it's fixed now by using the onResult event hook on the query, so it will execute the mutation afterwards.

onResult(handler): Event hook called when a new result is available.

export default defineComponent({
  setup(_, { root }) {
    const {
      loading: queryLoading,
      error: queryError,
      onResult: onQueryResult,
    } = useViewerQuery(() => ({
      enabled: isAuthenticated.value,
    }))

    const {
      mutate: setDefaultPreferences,
      loading: mutationLoading,
      error: mutationError,
    } = useSetPreferenceDefaultMutation({
      variables: {
        language: 'en-us',
        darkMode: false,
      },
    })

    onQueryResult((result) => {
      if (!result.data.viewer.preference) {
        void setDefaultPreferences()
      }
    })

    return {
      isAuthenticated,
      loading: queryLoading || mutationLoading,
      error: queryError || mutationError,
    }
  },
})