vuejs / apollo

🚀 Apollo/GraphQL integration for VueJS
http://apollo.vuejs.org
MIT License
6k stars 519 forks source link

`useQuery` outside of component crashes hydration #1455

Open NielsJanssen opened 1 year ago

NielsJanssen commented 1 year ago

Describe the bug Since 4.0.0-beta.2 using useQuery outside of a component, for example in router middleware, will prevent hydration entirely without any noticeable error. Changing the fetch policy to prevent caching prevents the issue, as well as using useAsyncQuery instead.

To Reproduce Create a router middleware that calls useQuery, for example:

import pageQuery from '~/graphql/queries/pages/page.gql';

export default defineNuxtRouteMiddleware((route) => {
  const currentPage = useState('currentPage', () => ({}));

  return new Promise((resolve, reject) => {
    const slug = route.path.replace(/^\//, '');
    const {onResult, onError} = useQuery(pageQuery, {segments: slug === '' ? 'home' : slug});

    onResult((pageResult) => {
      currentPage.value = pageResult.data.page;

      resolve();
    });

    onError(reject);
  });
});

Expected behavior In 4.0.0-beta.1 this code would work.

Versions vue: 3.2.47 vue-apollo: 3.7.7 @apollo/client: 3.7.7

Additional context It probably isn't desirable to use useQuery for this use case and I was better off using useAsyncQuery instead. However the issue that hydration is prevented entirely without error did cause my colleagues and I to lose quite a few hours debugging.

websitevirtuoso commented 1 year ago

I am using queries and mutations without without any issue. you just have to use apoloInstance and use it in native way

example mutation


import { provideApolloClient } from '@vue/apollo-composable'
import { apolloDefaultClient } from '@/plugins/apollo/vue-apollo'
import NotificationDeleteAll from '../graphql/mutations/notificationDeleteAll.gql'
import { toRawRecursive } from '@/modules/home/utils'
import { DocumentNode } from 'graphql/index'
import { TypedDocumentNode } from '@graphql-typed-document-node/core'

provideApolloClient(apolloDefaultClient)
const notification = useNotification()
const defaultClient = useApolloClient('default').client

const { mutate, loading, onError, onDone } = useMutation(NotificationDeleteAll)

onDone(() => {
  notification.success('All Notifications Deleted')
})

export default function useMutationNotificationDeleteAll() {
  const notificationDeleteAll = (query: DocumentNode | TypedDocumentNode, variables: object) => {
    mutate(
      {},
      {
        update: () => {
          const rawVariables = toRawRecursive(variables)
          const apolloCachedData = defaultClient.cache.readQuery({ query, variables: rawVariables })
          if (!apolloCachedData) return

          const newData = {
            myNotifications: {
              ...apolloCachedData.myNotifications,
              total: 0,
              hasMorePages: false,
              data: [],
            },
          }
          defaultClient.cache.writeQuery({ query, variables: rawVariables, data: newData })
        },
      }
    )
  }

  return { notificationDeleteAll, mutate, loading, onError, onDone }
}

the same with queries