もふもふ技術部

IT技術系mofmofメディア

(GraphQL+Rails+React)無限ページネーション

はじめに

UserとPostが1対多で結びついているような状況で、userとpostを一度 に取得することを想定しています。

記事について

graphql-ruby初学者向けの記事を書いています。

関連記事

  1. graphql-batchでN+1を解消してみた
  2. 無限ページネーション(現在の記事)
  3. 個人開発のcodegen.ymlの設定について考えてみた
  4. ファイルアップロード機能を実装してみた

使用技術

ruby 3.1.2
rails 7.0.3.1
graphql 2.0.13
react 18.2.0
apollo client 3.6.9

バックエンド

module Queries
  class Users < Queries::BaseQuery

    type ObjectTypes::UserType.connection_type, null: false

    def resolve
      User.all
    end
  end
end

connection_typeメソッドを付けるだけで完了です!

{
  users(first: 3, after: "", before: "") {
    edges {
      cursor
      node{
        id
        name
      }
    }
    pageInfo {
      hasPreviousPage
      hasNextPage
      startCursor
      endCursor
    }
  }
}

first 最初の何件を表示するかを設定できます。 after before cursorを設定し、どこを基準に取得するかを決めることができます。 例えば下記のGraphiQLの画像を参考に場合、afterにidが1のユーザーのcursor"MQ"を設定すると、idが2のユーザーから表示されることになります。 hasPreviousPage hasNextPage 前のページの有無、次のページの有無でtrue falseを返します。 Image from Gyazo

フロントエンド

import { relayStylePagination } from "@apollo/client/utilities";

const client = new ApolloClient({
  cache: new InMemoryCache({
    typePolicies: {
      Query: {
        fields: {
          users: relayStylePagination(),
        },
      },
    },
  }),
  link: authLink.concat(httpLink),
});
export const Users = () => {
  const { data: { users } = {}, fetchMore } = useUsersQuery({
    variables: {
      first: 20,
    },
  });
  const onClickAddPage = () => {
    if (users?.pageInfo.hasNextPage) {
      fetchMore({
        variables: {
          after: users.pageInfo.endCursor,
        },
      });
    }
  };

  return (
    <>
      {users?.edges?.map((user) => (
        <ul key={user?.node?.id}>
          <li>{user?.node?.title}</li>
        </ul>
      ))}
      //次のページが存在する時のみもっとみるを表示
      {users?.pageInfo.hasNextPage && (
        <button onClick={onClickAddPage}>もっとみる</button>
      )}
    </>
  );
};

元々userが20件表示されており、もっとみるボタンで追加のuserを取得し、最初の20件にマージされすることで、合計40件を表示するようにしています。

オフセットベースのページネーションについて考えてみた

Googleブラウザのようなページネーションを実装する時はgem等で実装するのが良い気がしてます。 普通に実装しようと思うとSQLでOFFSETやLIMITを発行することになると思いますが、データ数が増えればパフォーマンスの低下を招きます。 そこでpagyなるgemがありました。データ数が増えても速度はあんまり変わらないみたいなので良さそうでした。 https://github.com/ddnexus/pagy https://ddnexus.github.io/pagy/index#gsc.tab=0

会社の紹介

株式会社 mofmof では一緒に働いてくれるエンジニアを募集しています。 興味のある方は是非こちらのページよりお越しください! https://www.mof-mof.co.jp/ https://www.mof-mof.co.jp/recruit/