使用React和Ruby来实现类似页面编号的GraphQL页面分页功能

对于GraphQL的分页实现感觉很简单,但因为默认不提供获取页码的功能,所以经过一番尝试和困惑后,我总算勉强实现了带有(伪造的)页码的GraphQL分页功能。在此记录一下作为备忘。

如标题所示,该页面没有实际的页码。无法指定页码去查看页面内容,但可以显示当前所在位置。

用过的东西

    • graphql: 14.5.8

 

    • React: 16.12.0(Hooks使います)

 

    • Ruby: 2.6.2

 

    • Rails: 5.2.3

 

    material-ui/core”: 4.7.1

可以做的事情

    • ページネーションでページ番号を表示(正確には何件目〜何件目の表示)

 

    全件数の表示
Screen Shot 2019-12-17 at 12.25.37.png

我从Material-UI的文档中找到了这个内容,但是您如果看一下右下方,会发现显示着 “1-5 of 13″。这意味着显示了13件中的第1至第5件。我会将其实现。

做不到的事情 (Zhù bù de

    • 指定したページ番号への遷移

 

    ページ内行数の指定

根据上图所示,我们不会实现通过页码进行页面导航(我不太懂如何实现)。
另外,我们也不会指定页面内的行数(即每页显示多少项)。(因为在这次项目中我不需要,所以没有实现。)

实施

GraphQL端

首先,我们需要编写GraphQL查询。

import gql from 'graphql-tag';

export const getDesserts = gql`
  query desserts(
    $first: Int
    $after: String
    $last: Int
    $before: String
  ) {
    desserts(
      first: $first
      after: $after
      last: $last
      before: $before
    ) {
      totalCount
      edges {
        cursor
        node {
          id
          calorie
          fat
          carb
          protein
        }
      }
      pageInfo {
        endCursor
        hasNextPage
        startCursor
        hasPreviousPage
      }
    }
  }
`;

鼠标之类的说明可以通过搜索得到各种结果,所以稍微省略一下。
一般的GraphQL分页实现会返回edges和pageInfo,还会有一个名为totalCount的属性。一般情况下,这个属性是没有定义的,所以稍后会定义并确保它有正确的返回值。

因为目前没有定义,所以如果继续提交查询,会返回以下错误。因为没有定义!

{
  "errors": [
    {
      "message": "Field 'totalCount' doesn't exist on type 'DessertsConnection'",
    }
  ]
}

接下来,我们将实现自定义连接。
该连接提供了实现GraphQL分页功能(包括游标和页面信息等)的功能。
我们将在这个连接中添加total_count,以返回记录的总数。


class DessertsEdgeType < GraphQL::Types::Relay::BaseEdge
  node_type(Types::DessertType)
end

class Types::DessertsConnection < GraphQL::Types::Relay::BaseConnection
  field :total_count, Integer, null: false
  def total_count
    object.nodes.size
  end
  edge_type(DessertsEdgeType)
end

查询类型的实现如下。

module Types
  class QueryType < Types::BaseObject

    field :public_notifications, Types::DessertsConnection, null: false do
      description 'A list of all desserts'
      argument :first, Int, required: false # ページに表示するレコード数(nextで来た時)
      argument :after, String, required: false # レコードにつくID。このIDの直後のレコードからfirst分の件数を表示する
      argument :last, Int, required: false # ページに表示するレコード数(prevで来た時)
      argument :before, String, required: false # レコードにつくID。このIDの直前のレコードからlast分の件数を表示する
    end
    def public_notifications()
      Dessert.all
    end
  end
end

如果传递参数 first:5, after:’MQ32’,它将显示从ID为MQ32的记录之后的5条记录。(此ID是由GraphQL自动分配的。)

前端。

由于将所有表格都列举出来会使内容变多,所以我只摘录与分页有关的部分。


// 親コンポーネント
export const DessertsParent = props => {
   const [queryVariables, setQueryVariables] = useState({
    first: 10,
  });

  const [page, setPage] = useState(0);

  // デザートのデータを取ってくるクエリ
  const { data } = useDessertsQuery({
    variables: { ...queryVariables },
  });
  const desserts = data;

  // クエリに使う情報とページ番号の更新を行う関数
  const paginationEventHandler = (recordRangeInfo, newPage) => {
    setQueryVariables({ ...recordRangeInfo });
    setPage(newPage);
  };

  return(
   <>
     <Child
       desserts={desserts} // 表示するレコード
       paginationEventHandler={paginationEventHandler} // ページネーションで使う関数
       page={page} // ページ番号
     />
   </>
   );
}


// 子コンポーネント
import { TablePagination } from '@material-ui/core'

export const DessertsChild = props => {
  const { desserts, paginationEventHandler, page } = props;

  const handleChangePage = (event, newPage) => {
    let directedPage;
    if (page - newPage < 0) {
      // next page
      directedPage = { // 次のページを取得するための情報
        after: desserts
          ? desserts.desserts.pageInfo.endCursor
          : undefined,
        first: 10,
      };
    } else {
      // previous page
      directedPage = { // 前のページを取得するための情報
        before: desserts
          ? desserts.desserts.pageInfo.startCursor
          : undefined,
        last: 10,
      };
    }
    paginationEventHandler(directedPage, newPage);
  };
 return(

   <TablePagination
     component="div"
     count={
       desserts ? desserts.desserts.totalCount : 0
     }
     onChangePage={handleChangePage}
     page={page}
     rowsPerPage={10} // 1ページに表示する件数(今回は10で固定)
     rowsPerPageOptions={[10]} // 1ページに表示する件数のオプション(今回は10だけなので10のみ配列で渡す)
        />
 )

我已经可以通过这个来获取数量以及下一页和上一页的信息。只要调整连接,就可以获取到各种信息,所以我想试一试。(包括页面编号等,只要调整这里就可以获取到)

文献引用

广告
将在 10 秒后关闭
bannerAds