GatsbyJSのサイトにページャーを追加

GatsbyJSで作ったサイト日本の一覧を表示すると数が多いとページャーで分割して表示する。

　Gatsbyとページャーで検索すると「Adding Pagination」で追加する方法があるが、別のページが生成されるので目的とは違った。

 　そこで、ReactPaginateを使って画面に表示する内容を切り替える。
  渡すデータは次の形式のjson。実際のデータは１０個以上の大きさを渡している。データの取得はPA-APIを利用している。

  実際の表示
  
  https://kyukyunyorituryo.github.io/kindle_sale/20240704s42010/

  
 ```json

[
 {
  "Asin": "B0CPPC5RKF",
  "URL": "https://www.amazon.co.jp/dp/B0CPPC5RKF?tag=99hatena-22&linkCode=ogi&th=1&psc=1",
  "ImageURL": "https://m.media-amazon.com/images/I/51lVHGs0ZDL._SL500_.jpg",
  "Publisher": "KADOKAWA",
  "Contributor": "脇岡こなつ(著)",
  "Booktype": "Kindle版",
  "Title": "なぜかＳ級美女達の話題に俺があがる件２【電子特別版】 (角川スニーカー文庫)",
  "Price": 616,
  "Category": "ライトノベル,ライトノベル,日本の小説・文芸",
  "Points": 6
 },
 {
  "Asin": "B0C5L6KT9F",
  "URL": "https://www.amazon.co.jp/dp/B0C5L6KT9F?tag=99hatena-22&linkCode=ogi&th=1&psc=1",
  "ImageURL": "https://m.media-amazon.com/images/I/51qz+212n7L._SL500_.jpg",
  "Publisher": "KADOKAWA",
  "Contributor": "脇岡こなつ(著)",
  "Booktype": "Kindle版",
  "Title": "なぜかＳ級美女達の話題に俺があがる件 (角川スニーカー文庫)",
  "Price": 581,
  "Category": "ライトノベル,ライトノベル,日本の小説・文芸",
  "Points": 6
 },
 {
  "Asin": "B0CVRCWBKL",
  "URL": "https://www.amazon.co.jp/dp/B0CVRCWBKL?tag=99hatena-22&linkCode=ogi&th=1&psc=1",
  "ImageURL": "https://m.media-amazon.com/images/I/51b6J-FJmTL._SL500_.jpg",
  "Publisher": "KADOKAWA",
  "Contributor": "木嶋 隆太(著)",
  "Booktype": "Kindle版",
  "Title": "妹の迷宮配信を手伝っていた俺が、うっかりＳランクモンスター相手に無双した結果がこちらです【電子特別版】 (角川スニーカー文庫)",
  "Price": 616,
  "Category": "ライトノベル,ライトノベル,日本の小説・文芸",
  "Points": 6
 },]
 ```
Amazonsコンポーネントで受け取って画面に表示する。このコンポーネントをページャーで分割する。
 ```js
 const Amazons = ({ book }) => {

//数の制限
//book.length=20
var image_m
var image_s
for (let i = 0; i < book.length; i++) {
image_m=book[i].ImageURL.replace(/_SL500_/, '_SL160_');
image_s=book[i].ImageURL.replace(/_SL500_/, '_SL75_');
book[i].image_m=image_m;
book[i].image_s=image_s;
}
 //重複の削除
//https://qiita.com/allJokin/items/28cd023335641e8796c5
 const uniqueUsers = Array.from(new Map(book.map((user) => [user.Asin, user])).values()
);
    return (
    <div  id="book">
      {uniqueUsers.map(e => (
     <div key={e.Asin}>
        <a className="amazon-card-container" target="_blank" rel="noopener noreferrer" href={e.URL}>
          <div className="amazon-card-body">
            <div className="amazon-card-title">{e.Title}</div>
            <div className="amazon-card-domain">価格：{e.Price}円、ポイント：{e.Points}、{e.Contributor}、出版社：{e.Publisher}、カテゴリー：{e.Category}</div>
          </div>
          <div className="amazon-card-image-container">
          <img className="amazon-card-image"
           srcSet={`${e.image_s} 320w, ${e.image_m} 640w, ${e.ImageURL} `}
     src={e.image_s}
     sizes="(max-width:1280px) 50vw, 1280px"
      loading="lazy" alt={e.Title}/>
          </div>
        </a>
      </div>
      ))}
      
    </div>
    )
}
 ```
 react-paginateのusageをもとにAmazonsコンポーネントを利用して表示に書き換えた。上下にページネーションを表示している。
 
```js
import React, {  useState } from 'react';

import ReactPaginate from 'react-paginate';
import Amazons from "../components/amazons"

const Paginate = ({ itemsPerPage,items }) => {
  function Items({ currentItems }) {
    return (
      <>
<Amazons book={currentItems} />
      </>
    );
  }
    // Here we use item offsets; we could also use page offsets
    // following the API or data you're working with.
    const [itemOffset, setItemOffset] = useState(0);
  
    // Simulate fetching items from another resources.
    // (This could be items from props; or items loaded in a local state
    // from an API endpoint with useEffect and useState)
    const endOffset = itemOffset + itemsPerPage;
//    console.log(`Loading items from ${itemOffset} to ${endOffset}`);
    const currentItems = items.slice(itemOffset, endOffset);
    const pageCount = Math.ceil(items.length / itemsPerPage);
  
    // Invoke when user click to request another page.
    const handlePageClick = (event) => {
      const newOffset = (event.selected * itemsPerPage) % items.length;
      console.log(
        `User requested page number ${event.selected}, which is offset ${newOffset}`
      );
      setItemOffset(newOffset);
    };
  
    return (
      <>
           <ReactPaginate
          breakLabel="..."
          nextLabel="次へ>"
          onPageChange={handlePageClick}
          pageRangeDisplayed={3}
          pageCount={pageCount}
          previousLabel="<前へ"
          renderOnZeroPageCount={null}
          containerClassName={'pagination'} /* as this work same as bootstrap class */
subContainerClassName={'pages pagination'} /* as this work same as bootstrap class */
activeClassName={'active'} /* as this work same as bootstrap class */
        />
        <Items currentItems={currentItems} />
        <ReactPaginate
          breakLabel="..."
          nextLabel="次へ>"
          onPageChange={handlePageClick}
          pageRangeDisplayed={3}
          pageCount={pageCount}
          previousLabel="<前へ"
          renderOnZeroPageCount={null}
          containerClassName={'pagination'} /* as this work same as bootstrap class */
subContainerClassName={'pages pagination'} /* as this work same as bootstrap class */
activeClassName={'active'} /* as this work same as bootstrap class */
        />
      </>
    );
  }

export default Paginate

```
スタイルシートは下記記事を下にクラスを割り当てている。

https://stackoverflow.com/questions/52477591/react-pagination-styling-in-global-css-not-working

参考

 
 https://www.gatsbyjs.com/docs/adding-pagination/

 https://qiita.com/morieeeenyo/items/fe9f2c68ea824f5e5537

 https://github.com/AdeleD/react-paginate

 https://qiita.com/99nyorituryo/items/e337e6a75c361521f297