nuxt.jsvuejs3vue-composition-apinuxt3.jsvue-apollo

What is the proper way to query with NuxtApollo in Nuxt3


I have been using Nuxt2 and NuxtApollo for several years, but now I am trying to start a new project in Nuxt3 and seem to have some trouble adjusting to the new logic.

I have a minimal Nuxt3 installation with just the latest NuxtApollo package installed, as instructed in the documentation (https://apollo.nuxtjs.org/getting-started/quick-start). The @next version installed currently is 5.0.0-alpha.5.

Using the composables (https://apollo.nuxtjs.org/getting-started/composables) of NuxtApollo, I have no trouble with useAsyncQuery nor useLazyAsyncQuery.

Things start go south when I try fetch with the useQuery composable, which is recommended as the main way of querying:

useQuery: This is the primary method of querying your GraphQL server, unlike useAsyncQuery which is best used for initially fetching data in SSR applications, useQuery can comfortably be used in any scenario.

The useQuery composable does not return a promise. In my -probably incorrect- approach, this introduces the problem of not knowing when the query has returned without using a watcher.

For example this one returns undefined:

    const myVal = ref()

    const testQuery = () => {
        const { result } = useQuery(query, variables)
        myVal.value = result.value
        console.log(result.value) // undefined
    }

Using a watcher works but seems terribly wrong for several reasons:

    const testQuery = () => {
        const { result } = useQuery(query, variables)
            watch(result, () => {
            if(result.value){
                myVal.value = result.value
                console.log(result.value) // valid value
            }
        })
    }

The closest I have got to a proper usage is moving the query to setup and enabling it later:

    const queryEnabled = ref(false)
    const { result } = useQuery(query, null ,{enabled: queryEnabled})

    const test = () => {
        queryEnabled.value = true
    }

But again, if I needed to process or assign the returned value to a variable of my choice, I would need to utilize a watcher.

I suppose none of these problems would exist if the useQuery composable returned a promise that we could await.

I would much appreciate it if you could point me in the right direction as I have a very strong feeling that I'm missing something fundamental here.


Solution

  • As I see, you try to get a result immediately, but result.value will appear a little bit later, after a query processing.

    I see 3 approaches here:

    First approach - use result ref directly on top of the setup function:

    <script setup>

    /**
     * `myVal` - it's your ref, it's value will be undefined first,
     *  after query you will get a result there.
     */
    const { result: myVal } = useQuery(query, variables)
    

    Second approach - use onResult callback and assign a result to your ref:

    <script setup>

    const myVal = ref()
    
    const { onResult, onError } = useQuery(query, variables);
    
    onResult((result) => (myVal.value = result.data));
    onError((err) => (myVal.value = err));
    

    Third approach - use a proper function, useAsyncQuery:

    <script setup>

    const myVal = ref()
    
    // Async function
    const test = async () => {
      const { data } = await useAsyncQuery(query, { ...variables })
      
      myVal.value = data
    }
    
    test()