Closed6
Next.js x NestJS x GraphQLでページングを実装する
開発ステップ
- NestJSでのページング対応
- Next.jsでのページング対応
- 無限スクロールのライブラリを使ってUI作成
GraphQL ページネーションの代表的な実装手法
GraphQLのページネーション実装方法で有名なもので以下の2つが存在する
- Offset-basedページネーション
- Cursor-basedページネーション
今回は2を採用する
ページネーションと無限スクロール、その有用性について
そもそもWebにおいて無限スクロールってあんまり見ないなと思ったので調査。
結論
別ウィンドウでnページ以降を表示する方法と無限スクロール機能を使って同一ページ内にnページ以降の内容を表示をする方法の2つがあるが、Googleはどちらも推奨している。
ただ、サイトの特性によってはどちらがユーザーにとって使いやすいかは分かれるのでユーザー行動を適宜解析することが重要
以下の記事を参考にこのようなIOになった。
UsersInput
{
first: number,
after: string
}
UsersOutput
{
pageInfo: PageInfo,
edges: {node: UserOutput}[]
}
GraphQLの型をジェネリクスで指定できないのどうやって突破しようかな
import { Type } from '@nestjs/common'
import { Field, InputType, ObjectType } from '@nestjs/graphql'
@ObjectType()
export class PageInfo {
@Field()
endCursor: string
@Field()
hasNext: boolean
}
type Edge<T> = {
cursor: string
node: T
}
type IPaginatedType<T> = {
pageInfo: PageInfo
edges: Edge<T>[]
}
@InputType()
export class PaginatedInput {
@Field()
first: number
@Field()
after: string
}
export function Paginated<T>(classRef: Type<T>): Type<IPaginatedType<T>> {
@ObjectType(`${classRef.name}Edge`)
abstract class EdgeType {
@Field()
cursor: string
@Field()
node: T
}
@ObjectType({ isAbstract: true })
abstract class PaginatedType implements IPaginatedType<T> {
@Field()
pageInfo: PageInfo
@Field()
edges: EdgeType[]
}
return PaginatedType as Type<IPaginatedType<T>>
}
Undefined type error. Make sure you are providing an explicit type for the "node" of the "EdgeType" class.
解決した。
修正箇所としては以下
import { Type } from '@nestjs/common'
import { Field, InputType, ObjectType } from '@nestjs/graphql'
@ObjectType()
export class PageInfo {
@Field()
endCursor: string
@Field()
hasNext: boolean
}
type Edge<T> = {
cursor: string
node: T
}
type IPaginatedType<T> = {
pageInfo: PageInfo
edges: Edge<T>[]
}
@InputType()
export class PaginatedInput {
@Field()
first: number
- @Field()
+ @Field({ nullable: true })
after: string
}
export function Paginated<T>(classRef: Type<T>): Type<IPaginatedType<T>> {
@ObjectType(`${classRef.name}Edge`)
abstract class EdgeType {
@Field()
cursor: string
- @Field()
+ @Field(() => classRef)
node: T
}
@ObjectType({ isAbstract: true })
abstract class PaginatedType implements IPaginatedType<T> {
@Field()
pageInfo: PageInfo
- @Field()
+ @Field(() => [EdgeType], { nullable: 'items' })
edges: EdgeType[]
}
return PaginatedType as Type<IPaginatedType<T>>
}
勘所としては以下
- nullableを指定する際の注意点
- 対象が配列ならば
items
oritemsAndList
- 配列でなければboolean
- 対象が配列ならば
- ジェネリクスを使用している場合はGraphql側に型を教えてあげる必要があるため
returnTypeFunction
を記載する
このスクラップは2022/07/29にクローズされました