LoginSignup
6
8

More than 5 years have passed since last update.

React + Laravel のページネーションについて

Last updated at Posted at 2019-01-28

React + Laravel のページネーションについて

初めまして、Qiita初投稿です!

$ php artisan preset react
スカフォールドをvueからreactに切り替えている前提でお話します。

今回は以下のような地方のイベント一覧のサンプルを作成しました。
スクリーンショット 2019-01-28 14.51.29.png

lalavelのページネーション機能について

今回laravel側のAPI実装についての説明は端折らせて頂きますが一応ページネーション機能についてはざっとおさらいします。
クエリビルダやEloquentの最後にpagenateメソッドを追加すると簡単に実装できます。

Eloquentの場合:モデル名::get()->paginate(1ページあたり表示させたい行数)

作成したAPIにリクエストを送ると
スクリーンショット 2019-01-28 15.25.28.png

↑のようなJSONが返ってきます。
実際のデータはdataプロパティの中にpaginateで指定した数だけ入っています。

スクリーンショット 2019-01-28 15.33.03.png
表示に使用するキーはid,title,image_path_start_date,addresのみです。

以下のメタ情報を使ってreactでページネーションを実装していきましょう。

キー 内容
current_page 現在読み込んでいるページ
per_page 1ページあたりの取得件数(今回は6)
total 総件数

reactでのview実装

「react-js-pagination」ライブラリを使用して実装してみました。

Example.js
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import Card from './Card';
import axios from 'axios';
import Pagination from 'react-js-pagination';
import './Index.css';

export default class Example extends Component {
  constructor(props) {
    super(props);
    this.state = {
      eventList: [],
      activePage: 1,
      itemsCountPerPage: 1,
      totalItemsCount: 1,
      pageRangeDisplayed: 10,
    }
    this.handlePageChange=this.handlePageChange.bind(this);
  }


  handlePageChange(pageNumber) {
    axios
    .get('/api/event?page=' + pageNumber)
    .then(({data}) => {
      this.setState({
        eventList: data.data,
        itemsCountPerPage: data.per_page,
        totalItemsCount: data.total,
        activePage: data.current_page,
      })
    });
  }

  componentDidMount() {
    this.handlePageChange(1)
  }

  render() {

    return (
      <div className="container">   
        <h2>一覧</h2>
        <div className="cardGroup">
          <div className="container card-wrap">
            <div className="row">
              {this.state.eventList.map((item) => (<Card
                key={item.id}
                title={item.title}
                imagePath={item.image_path}
                startDate={item.start_date}
                address={item.address}
                />))}
            </div>
            <Pagination
              activePage={this.state.activePage}
              itemsCountPerPage={this.state.itemsCountPerPage}
              totalItemsCount={this.state.totalItemsCount}
              pageRangeDisplayed={this.state.pageRangeDisplayed}
              onChange={this.handlePageChange}
              itemClass='page-item'
              linkClass='page-link'
            />
          </div>
        </div>
      </div>

    );
  }
}

react-js-paginationのパラメーターについて

            <Pagination
              activePage={this.state.activePage}
              itemsCountPerPage={this.state.itemsCountPerPage}
              totalItemsCount={this.state.totalItemsCount}
              pageRangeDisplayed={this.state.pageRangeDisplayed}
              onChange={this.handlePageChange}
              itemClass='page-item'
              linkClass='page-link'
            />
パラメータ名
activePage 現在表示しているページ番号
itemsCountPerPage ページあたりのアイテム数(今回は6)
pageRangeDisplayed !後述!
totalItemsCount アイテムの総数
onChange ページ切り替えの時に呼ぶ関数(ページ番号を渡す)

pageRangeDisplayed: 5の場合
スクリーンショット 2019-01-28 17.14.08.png

見た目のカスタマイズも可能! bootstrapのcssのclass名を入れています。
itemClass='page-item'
linkClass='page-link'

詳細はnpmを見てください
https://www.npmjs.com/package/react-js-pagination

これらをstateとして持たせますので初期値を入れておきます

  constructor(props) {
    super(props);
    this.state = {
      eventList: [],
      activePage: 1,
      itemsCountPerPage: 1,
      totalItemsCount: 1,
      pageRangeDisplayed: 5,
    }
    this.handlePageChange=this.handlePageChange.bind(this);
  }

onChangeから呼び出すhandlePageChangeを作成

axiosを使用しています
ページ番号が引数として渡されるのでAPIのURLに?page=ページ番号のパラメータを付けてリクエストします。返ってきたデータはstateに入れましょう。

  handlePageChange(pageNumber) {
    axios
    .get('/api/event?page=' + pageNumber)
    .then(({data}) => {
      this.setState({
        eventList: data.data,
        itemsCountPerPage: data.per_page,
        totalItemsCount: data.total,
        activePage: data.current_page,
      })
    });
  }

ページ切り替えのボタンを押すとstateが更新され再レンダリングされます

            <div className="row">
              {this.state.eventList.map((item) => (<Card
                key={item.id}
                title={item.title}
                imagePath={item.image_path}
                startDate={item.start_date}
                address={item.address}
                />))}
            </div>

マウント時に初期表示するデータを取得する

  componentDidMount() {
    this.handlePageChange(1)
  }

おまけCardコンポーネント作成

Card.js
import React, {Component} from 'react';

export default class Card extends Component {
  constructor(props) {
    super(props);

  }

  render() {
    return (
      <div className="col-lg-4">
        <div className="card mb-4 box-shadow rounded-5">
          <p className="group-badge">イベント</p>
          <img className="card-img w-100 d-block rounded-0" style={{padding: 3}} src={this.props.imagePath}></img>
          <div className="card-body">
            <h4 className="card-title">{this.props.title}</h4>
            <h6 className="text-muted card-subtitle mb-2"></h6>
            <div className="card-detail"></div>
            <div className="card-text">
              <p>
                <i className="fa fa-calendar"></i>
                {this.props.startDate}
              </p>
              <p>
                <i className="fa fa-map-marker"></i>
                {this.props.address}
              </p>
            </div>
            <a className="card-link" href="#">#仮タグ</a>
            <a className="card-link" href="#">#仮タグ</a>
          </div>
        </div>
      </div>
    )
  }
}

bootstrapStudioで作成しました。タグ多すぎ?cssを弄っているので、サンプル画像と表示が異なると思います。小コンポーネントへの受け渡しの参考までに。。

6
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
8