apollo icon indicating copy to clipboard operation
apollo copied to clipboard

Vue-Apollo v4 documentation doesn't follow Apollo Client v3 documentation

Open MechJosh0 opened this issue 3 years ago • 15 comments

In the documentation regarding pagination, it guides the user to use updateQuery. However, in ApolloClient v3 this is deprecated with a warning that it will be removed in the next major version.

https://v4.apollo.vuejs.org/guide-composable/pagination.html

The updateQuery callback for fetchMore is deprecated, and will be removed
in the next major version of Apollo Client.

Please convert updateQuery functions to field policies with appropriate
read and merge functions, or use/adapt a helper function (such as
concatPagination, offsetLimitPagination, or relayStylePagination) from
@apollo/client/utilities.

The field policy system handles pagination more effectively than a
hand-written updateQuery function, and you only need to define the policy
once, rather than every time you call fetchMore.

MechJosh0 avatar Dec 09 '20 13:12 MechJosh0

Removed.

MechJosh0 avatar Dec 09 '20 13:12 MechJosh0

Yes. Please update the documentation ASAP! Thank you!

Gyurmatag avatar Dec 24 '20 17:12 Gyurmatag

@Gyurmatag If you're looking for help right now, you can review the Apollo Client v3 pagination documentation.

I'm not sure if @Akryum will even update his documentation to include how to handle pagination, as it now relies upon the setup of Apollo Client and is outside of his module scope. It may be best to simply have a page which directs the developer to the Apollo Client pagination documentation.

MechJosh0 avatar Dec 31 '20 11:12 MechJosh0

I hope it will get updated, because it is confusing and it would be so much easier to have this in the v4 documentation.

Gyurmatag avatar Jan 03 '21 09:01 Gyurmatag

The link I provided is all you need for pagination documentation.

There isn't anything additional that Vue apollo v4 needs to document about pagination because it's all in the Apollo Client documentation.

MechJosh0 avatar Jan 03 '21 10:01 MechJosh0

Thanks, but I am a little bit confused about the Apollo Client documentation. So here I have this implementation (according to the docs):

setup () {
    const { result: quotesResult, loading: quotesLoading, subscribeToMore, fetchMore } = useQuery(quotesQuery, { limit: 5 })
    const quotes = useResult(quotesResult, null, data => data.quotes)

    function loadMore () {
      fetchMore({
        variables: {
          limit: 5,
          next: quotes.value.next
        },
        updateQuery: (previousResult, { fetchMoreResult }) => {
          return {
            ...previousResult,
            quotes: {
              ...previousResult.quotes,
              next: fetchMoreResult.quotes.next,
              results: [
                ...previousResult.quotes.results,
                ...fetchMoreResult.quotes.results
              ]
            }
          }
        }
      })
    }

    return { quotes, quotesLoading, loadMore }
  }

How should I convert this to a not deprecated solution?

Thanks for the help in advance!

Gyurmatag avatar Jan 04 '21 17:01 Gyurmatag

@Gyurmatag

As per their Apollo Client 3 release announcement (and the console warning), we no longer want updateQuery on the fetchMore function, so you should go ahead and remove it entirely.

setup () {
    const { result: quotesResult, loading: quotesLoading, subscribeToMore, fetchMore, variables } = useQuery(quotesQuery, { limit: 5 })
    const quotes = useResult(quotesResult, null, data => data.quotes)

    function loadMore () {
      fetchMore({
        variables: {
          ...variables,
          next: quotes.value.next
        },
      })
    }

    return { quotes, quotesLoading, loadMore }
  }

Note: You'll notice how I imported variables from Vue Apollo as I discovered this to be very helpful with fetchMore for pagination and refetch for searching and ordering. This will obviously be up to you if you and your use case if you find it helpful or not.

You should then read about offset pagination helpers and keyArgs to learn how to implement the new pagination methods.

If you can use Apollo Clients pagination helpers, you should. Otherwise, you will need to create the pagination logic yourself:

// ApolloConfiguration.ts
import { ApolloClient, InMemoryCache, NormalizedCacheObject, FieldPolicy } from "@apollo/client";
import { offsetLimitPagination } from "@apollo/client/utilities"

...

function customOffsetLimitPagination(): FieldPolicy {
        // Your custom pagination logic should go here.
        // You can have a generic pagination helper which can go with all your pagination queries
        // this is the ideal solution and the reason why Apollo Client 3 did this method.
        // Or you will need to write a pagination helper per query field.
	...
}

export const cache: InMemoryCache = new InMemoryCache({
	typePolicies: {
		Query: {
			fields: {
				Foo: customOffsetLimitPagination(),
                                Bar: offsetLimitPagination(),
			},
		},
	},
});

export const apolloClient: ApolloClient<NormalizedCacheObject> = new ApolloClient({
	...
	cache,
});

MechJosh0 avatar Jan 04 '21 17:01 MechJosh0

Thanks for your long answer! I've got cursor pagination as you can see in my implementation. So probably I should examine this: https://www.apollographql.com/docs/react/pagination/cursor-based/

Gyurmatag avatar Jan 04 '21 18:01 Gyurmatag

@MechJosh0 Okay so here is whats happening to me: I've got quotes in the Apollo Cache, here it is:

image

Now I removed what you said from the loadMore() function. And then inserted this to my configs:

const cache = new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        quotes: {
          merge (existing, incoming, { readField }) {
            const quotes = existing ? { ...existing.results } : {}
            incoming.results.forEach(quote => {
              quotes[readField('_id', quote)] = quote
            })
            return {
              next: incoming.next,
              quotes
            }
          },

          read (existing) {
            if (existing) {
              return {
                next: existing.next,
                quotes: Object.values(existing.results)
              }
            }
          }
        }
      }
    }
  }
})

Now whenever I am calling the loadMore() function, the graphql call gets executed, but the results not merged together and not updating the ui. Instead in the cache I've got more quotes, like this:

image

Maybe there is a problem with the typePolicy? It doesnt get called at all...

Thanks for your help!

Gyurmatag avatar Jan 04 '21 19:01 Gyurmatag

@Gyurmatag I would expect your merge to look similar to that of your original merge logic from your updateQuery function. So something like:

          merge (existing, incoming) {
            if(!existing) return incoming;

            return {
              next: incoming.next,
              results: [...existing.results, ...incoming.results],
            }
          },

MechJosh0 avatar Jan 05 '21 08:01 MechJosh0

@MechJosh0 My problem is that my 'quotes' typePolicy doesn't get called at all. The merge() and read() function doesnt't executes. What can be the problem?

Gyurmatag avatar Jan 05 '21 16:01 Gyurmatag

Have you updated to Apollo Client 3 and followed it's migration?

And you will need to ensure the policy is written in the correct area depending on your graph query. This is something you'll need to work out and play around with.

query {
  quotes { 
    ..
  }
}
export const cache: InMemoryCache = new InMemoryCache({
	typePolicies: {
		user: {
			fields: {
				quotes: ///
			},
		},
	},
});

OR

query {
  user {
    quotes { 
      ..
    }
  }
}
export const cache: InMemoryCache = new InMemoryCache({
	typePolicies: {
		user: {
			fields: {
				quotes: ///
			},
		},
	},
});

There is a lot of documentation about type policies so I do recommend to go read everything you can.

MechJosh0 avatar Jan 05 '21 17:01 MechJosh0

@MechJosh0 I started the project with Apollo Client 3, and it worked great until now.

image

As you can see in this screenshot the quotes are PaginatedItems type, but I've tried that too, in the typePolicies like that and its not working:

  typePolicies: {
    Query: {
      fields: {
        paginatedItems: {
          merge (existing, incoming, { readField }) {
            console.log('asdsadasd')
            if (!existing) return incoming

            return {
              next: incoming.next,
              results: [...existing.results, ...incoming.results]
            }
          },

          read (existing) {
            console.log('asdsadasd')
            if (existing) {
              return {
                next: existing.next,
                results: Object.values(existing.results)
              }
            }
          }
        }
      }
    }
  }

Here is my query:

query Quotes($limit: Int, $next: String) {
  quotes(limit: $limit, next: $next) {
    results {
      _id
      text
      character { id }
    }
    previous
    hasPrevious
    next
    hasNext
  }
}

and this is what I get back:

{
  "data": {
    "quotes": {
      "results": [
        {
          "_id": "5fe4df242c075a2e881d4cec",
          "text": "fabian",
          "character": {
            "id": "5fb110ebcdb33d42188f00b8"
          }
        },
        {
          "_id": "5fe4db392c075a2e881d4ceb",
          "text": "ererererer",
          "character": {
            "id": "5f91c4db67f18650500f1bdb"
          }
        },
        {
          "_id": "5fe4db0e2c075a2e881d4cea",
          "text": "dfdf",
          "character": {
            "id": "5f91beb6b487003740bc0ed4"
          }
        },
        {
          "_id": "5fe21fe9ced20755500b6aa4",
          "text": "AAAAAAAAAAAAAAAA",
          "character": {
            "id": "5fb11194cdb33d42188f00b9"
          }
        },
        {
          "_id": "5fe1f4b4799bc730d061b469",
          "text": "dfsd",
          "character": {
            "id": "5f91c4db67f18650500f1bdb"
          }
        }
      ],
      "previous": "eyIkb2lkIjoiNWZlNGRmMjQyYzA3NWEyZTg4MWQ0Y2VjIn0",
      "hasPrevious": false,
      "next": "eyIkb2lkIjoiNWZlMWY0YjQ3OTliYzczMGQwNjFiNDY5In0",
      "hasNext": true
    }
  }
}

I have no idea why it is not working. Can you please help me?

Maybe I just wait till the Vue Apollo 4 docs gets into better shape... Hope I will find answers there specific to VueJS. However I started to feeling worried about this library. The last major version was months ago.. :(

Gyurmatag avatar Jan 05 '21 20:01 Gyurmatag

@MechJosh0 I started the project with Apollo Client 3, and it worked great until now.

image

As you can see in this screenshot the quotes are PaginatedItems type, but I've tried that too, in the typePolicies like that and its not working:

  typePolicies: {
    Query: {
      fields: {
        paginatedItems: {
          merge (existing, incoming, { readField }) {
            console.log('asdsadasd')
            if (!existing) return incoming

            return {
              next: incoming.next,
              results: [...existing.results, ...incoming.results]
            }
          },

          read (existing) {
            console.log('asdsadasd')
            if (existing) {
              return {
                next: existing.next,
                results: Object.values(existing.results)
              }
            }
          }
        }
      }
    }
  }

Here is my query:

query Quotes($limit: Int, $next: String) {
  quotes(limit: $limit, next: $next) {
    results {
      _id
      text
      character { id }
    }
    previous
    hasPrevious
    next
    hasNext
  }
}

and this is what I get back:

{
  "data": {
    "quotes": {
      "results": [
        {
          "_id": "5fe4df242c075a2e881d4cec",
          "text": "fabian",
          "character": {
            "id": "5fb110ebcdb33d42188f00b8"
          }
        },
        {
          "_id": "5fe4db392c075a2e881d4ceb",
          "text": "ererererer",
          "character": {
            "id": "5f91c4db67f18650500f1bdb"
          }
        },
        {
          "_id": "5fe4db0e2c075a2e881d4cea",
          "text": "dfdf",
          "character": {
            "id": "5f91beb6b487003740bc0ed4"
          }
        },
        {
          "_id": "5fe21fe9ced20755500b6aa4",
          "text": "AAAAAAAAAAAAAAAA",
          "character": {
            "id": "5fb11194cdb33d42188f00b9"
          }
        },
        {
          "_id": "5fe1f4b4799bc730d061b469",
          "text": "dfsd",
          "character": {
            "id": "5f91c4db67f18650500f1bdb"
          }
        }
      ],
      "previous": "eyIkb2lkIjoiNWZlNGRmMjQyYzA3NWEyZTg4MWQ0Y2VjIn0",
      "hasPrevious": false,
      "next": "eyIkb2lkIjoiNWZlMWY0YjQ3OTliYzczMGQwNjFiNDY5In0",
      "hasNext": true
    }
  }
}

I have no idea why it is not working. Can you please help me?

Maybe I just wait till the Vue Apollo 4 docs gets into better shape... Hope I will find answers there specific to VueJS. However I started to feeling worried about this library. The last major version was months ago.. :(

Got same issue trying to use TypePolicies for vue-composable queries and it doesn't seem to "see" TypePolicies for my field. In contrary, I used resolvers (deprecated) with the same query and they work.

It seems I will have to use deprecated resolvers until vue-composables will be compatible with TypePolicies :(

JoJk0 avatar Mar 04 '21 16:03 JoJk0

unknown

custom posts: { page: { edges pageInfo } }

how to add typePolicies in page ?

productdevbook avatar Mar 10 '22 12:03 productdevbook