ページに商品をたくさん並べるときにreact-paginateを使っていたが、上下のページ番号が連動しなかった。
import React, { useState } from "react";
import ReactPaginate from "react-paginate";
import Amazons from "../components/amazons";
const Paginate = ({ itemsPerPage, items }) => {
/* =====================
* state
* ===================== */
const [itemOffset, setItemOffset] = useState(0);
/* =====================
* pagination calculation
* ===================== */
const endOffset = itemOffset + itemsPerPage;
const currentItems = items.slice(itemOffset, endOffset);
const pageCount = Math.ceil(items.length / itemsPerPage);
/* =====================
* handlers
* ===================== */
const handlePageClick = (event) => {
const newOffset =
(event.selected * itemsPerPage) % items.length;
setItemOffset(newOffset);
};
/* =====================
* pagination component
* ===================== */
const pagination = (
<ReactPaginate
breakLabel="..."
previousLabel="<前へ"
nextLabel="次へ>"
pageCount={pageCount}
pageRangeDisplayed={3}
onPageChange={handlePageClick}
renderOnZeroPageCount={null}
containerClassName="pagination"
subContainerClassName="pages pagination"
activeClassName="active"
/>
);
/* =====================
* render
* ===================== */
return (
<>
{/* 上部ページネーション */}
{pagination}
{/* 商品一覧 */}
<Amazons book={currentItems} />
{/* 下部ページネーション */}
{pagination}
</>
);
};
export default Paginate;
You:
上下のページネーションの連動させて、できるだけ維持したまま
ChatGPT:
了解です。
「今の構造・見た目・書き方をできるだけ維持したまま、上下のページネーションだけを確実に連動させる」 ですね。
やることは 1点だけ です。
核心(これだけで連動する)
✅ currentPage を state で持ち、forcePage を使う
今は
itemOffsetだけを state 管理ReactPaginateは内部 state 任せ
なので、上下が同期しません。
最小変更版(ほぼそのまま)
import React, { useState } from "react"; import ReactPaginate from "react-paginate"; import Amazons from "../components/amazons"; const Paginate = ({ itemsPerPage, items }) => { /* ===================== * state * ===================== */ const [currentPage, setCurrentPage] = useState(0); /* ===================== * pagination calculation * ===================== */ const itemOffset = currentPage * itemsPerPage; const endOffset = itemOffset + itemsPerPage; const currentItems = items.slice(itemOffset, endOffset); const pageCount = Math.ceil(items.length / itemsPerPage); /* ===================== * handlers * ===================== */ const handlePageClick = (event) => { setCurrentPage(event.selected); }; /* ===================== * pagination component * ===================== */ const pagination = ( <ReactPaginate breakLabel="..." previousLabel="<前へ" nextLabel="次へ>" pageCount={pageCount} pageRangeDisplayed={3} onPageChange={handlePageClick} forcePage={currentPage} {/* ★連動の要 */} renderOnZeroPageCount={null} containerClassName="pagination" subContainerClassName="pages pagination" activeClassName="active" /> ); /* ===================== * render * ===================== */ return ( <> {/* 上部ページネーション */} {pagination} {/* 商品一覧 */} <Amazons book={currentItems} /> {/* 下部ページネーション */} {pagination} </> ); }; export default Paginate;
何を変えたか(超最小)
| 変更 | 理由 |
|---|---|
itemOffset → currentPage |
ページ番号を単一管理 |
handlePageClick |
offset計算を削除 |
forcePage={currentPage} |
上下同期 |
| JSX構造 | そのまま |
なぜこれで上下が連動するのか
上の
ReactPaginateを押す
→setCurrentPage()
→ state 更新
→ 上下のforcePageが同時に更新下を押しても同じ流れ
「できるだけ維持」という条件について
✔ JSX構造は維持
✔ pagination 定数も維持
✔ Amazons の呼び出しも変更なし
✔ 見た目・CSS 影響なし
変更行数は実質 5 行程度 です。
追加でやると便利(任意)
フィルタ変更時に1ページ目へ戻す
useEffect(() => {
setCurrentPage(0);
}, [items]);
結論
上下のページネーションを連動させる唯一の正解は forcePage
この実装は
シンプル
壊れにくい
ReactPaginate 推奨
です。
次は
👉 ページ変更時にスクロールトップ
👉 モバイル用ページ数削減
どちらを足しますか?