diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-13 03:09:34 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-13 03:09:34 +0300 |
commit | 3cd08f4bf96cda3e9d3abf233095107832b17c20 (patch) | |
tree | dc09a618783a79d70f2a404374d4b850ccf9cc84 /doc/development/fe_guide | |
parent | dd4bee69b7d55620f7dc9db8c36b478bd4959755 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'doc/development/fe_guide')
-rw-r--r-- | doc/development/fe_guide/graphql.md | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md index d21c937bfe4..4a8fca3075b 100644 --- a/doc/development/fe_guide/graphql.md +++ b/doc/development/fe_guide/graphql.md @@ -258,6 +258,134 @@ export default { }; ``` +### Working with pagination + +GitLab's GraphQL API uses [Relay-style cursor pagination](https://www.apollographql.com/docs/react/data/pagination/#cursor-based) +for connection types. This means a "cursor" is used to keep track of where in the data +set the next items should be fetched from. + +Every connection type (for example, `DesignConnection` and `DiscussionConnection`) has a field `pageInfo` that contains an information required for pagination: + +```javascript +pageInfo { + endCursor + hasNextPage + hasPreviousPage + startCursor +} +``` + +Here: + +- `startCursor` and `endCursor` display the cursor of the first and last items + respectively. +- `hasPreviousPage` and `hasNextPage` allow us to check if there are more pages + available before or after the current page. + +When we fetch data with a connection type, we can pass cursor as `after` or `before` +parameter, indicating a starting or ending point of our pagination. They should be +followed with `first` or `last` parameter respectively to indicate _how many_ items +we want to fetch after or before a given endpoint. + +For example, here we're fetching 10 designs after a cursor: + +```javascript +query { + project(fullPath: "root/my-project") { + id + issue(iid: "42") { + designCollection { + designs(atVersion: null, after: "Ihwffmde0i", first: 10) { + edges { + node { + id + } + } + } + } + } + } +} +``` + +#### Using `fetchMore` method in components + +When making an initial fetch, we usually want to start a pagination from the beginning. +In this case, we can either: + +- Skip passing a cursor. +- Pass `null` explicitly to `after`. + +After data is fetched, we should save a `pageInfo` object. Let's assume we're storing +it to Vue component `data`: + +```javascript +data() { + return { + pageInfo: null, + } +}, +apollo: { + designs: { + query: projectQuery, + variables() { + return { + // rest of design variables + ... + first: 10, + }; + }, + result(res) { + this.pageInfo = res.data?.project?.issue?.designCollection?.designs?.pageInfo; + }, + }, +}, +``` + +When we want to move to the next page, we use an Apollo `fetchMore` method, passing a +new cursor (and, optionally, new variables) there. In the `updateQuery` hook, we have +to return a result we want to see in the Apollo cache after fetching the next page. + +```javascript +fetchNextPage() { + // as a first step, we're checking if we have more pages to move forward + if (this.pageInfo?.hasNextPage) { + this.$apollo.queries.designs.fetchMore({ + variables: { + // rest of design variables + ... + first: 10, + after: this.pageInfo?.endCursor, + }, + updateQuery(previousResult, { fetchMoreResult }) { + // here we can implement the logic of adding new designs to fetched one (for example, if we use infinite scroll) + // or replacing old result with the new one if we use numbered pages + + const newDesigns = fetchMoreResult.project.issue.designCollection.designs; + previousResult.project.issue.designCollection.designs.push(...newDesigns) + + return previousResult; + }, + }); + } +} +``` + +Please note we don't have to save `pageInfo` one more time; `fetchMore` triggers a query +`result` hook as well. + +#### Limitations + +Currently, bidirectional pagination doesn't work: + +- `hasNextPage` returns a correct value only when we paginate forward using `endCursor` + and `first` parameters. +- `hasPreviousPage` returns a correct value only when we paginate backward using + `startCursor` and `last` parameters. + +This should be resolved in the scope of the issue +[Bi-directional Pagination in GraphQL doesn't work as expected](https://gitlab.com/gitlab-org/gitlab/-/issues/208301). + ### Testing #### Mocking response as component data |