apollo icon indicating copy to clipboard operation
apollo copied to clipboard

onResult hook called while query still in flight

Open andgith opened this issue 1 year ago • 11 comments

Describe the bug When using onResult the hook is called while the query is still loading and contains no data. This is a change from previous behaviour, is this intended?

To Reproduce Add onResult hook to useQuery and log output:

onResult((queryResult) => { console.log(queryResult); });

Versions vue: 3.3.4 vue-apollo: 4.0.0-beta.7 @apollo/client: 3.4.13

image

andgith avatar Jun 14 '23 09:06 andgith

yes I have the same issue in latest 2 versions

websitevirtuoso avatar Jun 15 '23 21:06 websitevirtuoso

To fix it I have to write if to check result

onResult((queryResult) => {
if(queryResult.data !== undefined){
console.log(queryResult);
}
});

websitevirtuoso avatar Jun 15 '23 21:06 websitevirtuoso

image

const { onResult } = useQuery(GetPosts, { filter: { id: [route.params.id] } }, { clientId: 'public' })
const { mutate, loading, onDone, onError } = useMutation(PostUpsert)

onResult((queryResult) => {
  console.log('queryResult')
  console.log(queryResult)
  redirectNotFoundIfEmpty(queryResult.data.posts.data)
  ;({
    id: initialValues.id,
    title: initialValues.title,
    slug: initialValues.slug,
    status: initialValues.status,
    content: initialValues.content,
    category: { id: initialValues.category_id },
    meta_title: initialValues.meta_title,
    meta_keyword: initialValues.meta_keyword,
    meta_description: initialValues.meta_description,
  } = queryResult.data.posts.data[0])

  mediaItems.value = JSON.parse(JSON.stringify(queryResult.data.posts.data[0]))
})

Hope it can be fixed in repo

websitevirtuoso avatar Jun 16 '23 04:06 websitevirtuoso

anyone can check it please?

websitevirtuoso avatar Jul 07 '23 00:07 websitevirtuoso

According tests in repo

<script lang="ts" setup>
import { useQuery } from '@vue/apollo-composable'
import gql from 'graphql-tag'
import { ref } from 'vue'

const { onResult, loading } = useQuery(gql`
  query channel ($id: ID!) {
    channel (id: $id) {
      id
      label
      messages {
        id
        text
      }
    }
  }
`, {
  id: 'general',
})

const channel = ref<any>(null)

onResult((result) => {
  channel.value = result.data?.channel
})
</script>

<template>
  <div class="m-6 border border-green-500 rounded">
    <div
      v-if="loading"
      class="loading"
    >
      Loading...
    </div>

    <div
      v-if="channel"
      data-test-id="data"
    >
      <div>Loaded channel: {{ channel.label }}</div>
      <div>Messages: {{ channel.messages.length }}</div>
    </div>
  </div>
</template>

We should get result when it will be available. channel.value = result.data?.channel I tried to find working version to point or even made a PR for fix. but I failed and repo a bit complex in structure for me.

websitevirtuoso avatar Jul 07 '23 20:07 websitevirtuoso

Recently upgraded to the latest version and started having some weird problems. Only once I started looking around on the open issues did I discover this. Are there any planned changes/fixes for this? What is the best workaround?

lwpinion avatar Oct 31 '23 20:10 lwpinion

This is not a bug. IN my case this is proper behaviour. I have do always check if query in flight

const { onResult } = useQuery(GeMe, {}, () => ({ enabled: userState.authorized }))

onResult(({ data }) => {
  if (data === undefined) return
  userState.setUser(data.me)
  setPermissions(parseUserPermissions(data.me))
  userState.favorites = data.me.favorites.map((item: Favorite) => item.id)
})

Explaining why this is not bug. let's consider next query

#import "../fragments/listing.fragment.gql"
#import "../fragments/listingType.fragment.gql"
#import "../fragments/listingMedia.fragment.gql"

query GetListings($pagination: Pagination, $sort: Sortable, $filter: ListingFilter, $mediaOnlyPrimary: Boolean) {
  listings(pagination: $pagination, sort: $sort, filter: $filter) {
    data {
      ...ListingFragment
      type {
        ...ListingTypeFragment
      }
      media(filter: { is_primary: $mediaOnlyPrimary }) {
        ...MediaFragment
      }
      user {
        id
        first_name
        last_name
      }
    }
    total
    hasPages
    lastPage
    hasMorePages
  }
}

ON my vuejs I have pagination and I want don't reset parameters:

    total
    hasPages
    lastPage
    hasMorePages

So to do this I have next condition to empty key "data" but keep all other values to keep elements in place and in correct condition.

onResult(({ data }) => {
  // when we do preflight need to keep all values except items
  if (data === undefined) {
    listings.value = { ...listings.value, data: [] }
    return
  }

  listings.value = data.listings
})

I hope this will help everyone who had missunderstanding

websitevirtuoso avatar Nov 01 '23 19:11 websitevirtuoso

@websitevirtuoso thank you. Excuse me for asking. I understand that it is not a bug, but as type of "data" is not registered as a possibly undefined. Do you have any plans to resolve this issue?

image

qwertyuiopngsdfg avatar Nov 01 '23 19:11 qwertyuiopngsdfg

No I don't have any plans to solve it. If you don't like this behaviour you can write wrapper around result and skip preflight data and get data only when it will be available

websitevirtuoso avatar Nov 01 '23 21:11 websitevirtuoso

@qwertyuiopngsdfg It looks like it's an issue in Apollo Client:

https://github.com/apollographql/apollo-client/blob/9b22974b3e0f131a50c2618cc08ea6745e79a653/src/core/types.ts#L143

Akryum avatar Jan 15 '24 09:01 Akryum

@Akryum the same issue with @vue/apollo-composable 4.0.1 and @apollo/client 3.9.5

The error disappears if you set fetchPolicy: "no-cache", perhaps this can somehow help understand the reason for this behavior?

lermontex avatar Mar 03 '24 21:03 lermontex