React 前端分頁實作:從資料切片到分頁元件拆分

更新 發佈閱讀 9 分鐘

【分頁 (Pagination) 是什麼?前端與後端分頁實現方法與優劣分析】這篇文章中,簡單介紹了分頁是什麼,也包括了分頁的目的以及前端分頁與後端分頁的區別,本篇文章則會接著介紹我如何在 React 專案中實現前端分頁。

本篇文章專注於前端分頁的實作細節,關於為何選擇 Client-side Pagination ,或是你還不知道分頁是什麼,歡迎先閱讀上一篇文章!

對接下來內容有興趣的讀者歡迎繼續往下閱讀~~


專案背景

我目前開發的是一個 React + Vite 的部落格文章網站。在這個網站中也會同步分享許多程式設計相關的文章。因為文章數會在數十篇左右,考慮這個規模下我沒有建立資料庫,而是透過靜態網站存取資料,也因為是靜態網站,採取的分頁技術是前端分頁 (Client-side Pagination)。


組件架構

在進入實作細節前,先確認這個分頁設計的兩個組件與個別的職責:

父元件:Article.jsx

這個元件用來管理所有文章,原本的設計就是用 map 將所有的文章條列出來。現在要引入分頁技術,因此需要改寫這邊的檔案。

父元件需要控制資料的處理邏輯:

  • 狀態管理:持有原始文章列表、搜尋字串、以及當前的頁碼 (currentPage)。
  • 資料加工:執行搜尋過濾與分頁切片運算。
  • 分發指令:將計算好的分頁資訊(如當前頁數、總頁數)傳遞給子組件,並定義頁碼切換行為。

子元件:Pagination.jsx

這個元件就非常單純,只用於畫出我們想要的分頁按鈕 UI,並實現點及按鈕時跳轉頁面。

  • 渲染邏輯:根據父元件傳入的總頁數,計算何時該顯示數字、何時該顯示省略號。
  • 觸發事件:當使用者點擊頁碼時,呼叫父元件傳入的 callback function 來改變 currentPage

實作步驟

1. 資料切片 (Array Slicing):

在實現分頁前須要先確認幾個項目

  1. 每個分頁要呈現的資料數量
  2. 分頁數量
  3. 該分頁要呈現的是哪些資料
  4. 分頁按鈕顯示數量
const start = (currentPage - 1) * ITEMS_PER_PAGE; 
return filteredArticles.slice(start, start + ITEMS_PER_PAGE);

// 1. 設定初始值與預設值​
const [currentPage, setCurrentPage] = useState(1);
const ITEMS_PER_PAGE = 4;
const MAX_VISIBLE_PAGE = 3;

// 2. 計算總頁數
const totalPages = Math.ceil(filterArticles.length/ ITEMS_PER_PAGE);

// 3. 取得當前頁面要呈現的資料切片
const currentArticles = useMemo(()=>{
const start = (currentPage - 1 ) * ITEMS_PER_PAGE;
  return filterArticles.slice(start, start + ITEMS_PER_PAGE);
},[filterArticles, currentPage]);

// 4. 處理換頁用的函式
const handlePageChange = (page)=>{
setCurrentPage(page);
window.scrollTo({top: 0, behavior: "smooth"});
};
// 5. 將資料傳入 pagination 元件​
<Pagination
currentPage={currentPage}
totalPages={totalPages}
onPageChange={handlePageChange}
maxVisiblePsges={MAX_VISIBLE_PAGE}
/>
  • 透過 React 的 useState 記住目前是第幾頁 (currentPage),當前頁碼的初始值為 1、每頁呈現 4 篇文章、頁碼按鈕最多呈現 3 個。
  • 總頁數用「總文章數/每頁文章數」,用無條件進位,避免不能整除的數字造成資料遺漏。
  • 使用 JavaScript 原生的 .slice() 陣列切割語法,算好每頁的頭跟尾
  • 處理換頁的函式呼叫 setCurrentPage 切換 currentPage,當 currentPage 改變時會觸發 currentArticles 重新計算要陳列的資料。

2. 動態分頁元件 (<Pagination />):

用一個獨立的元件來畫出底部的頁碼。這個元件內部包含了一個省略號邏輯,如果總頁數非常多,元件會自動隱藏中間的數字並顯示省略號 (例如:1, 2, 3 ... 10),保持畫面整潔,而不會是一整排十幾個按鈕。

顯示頁碼前,需要先制定一下顯示的策略:

  1. 最多顯示 n 個連續數字按鈕
  2. 假設總頁數 <= n,一次顯示所有頁面按鈕 (例:n = 3,頁面只有3頁,一次顯示:1, 2, 3)
  3. 保留頭尾的數字按鈕,以及「以當前頁面為中心」的 n 個頁面按鈕 (例:1, ... 5, 6, 7, ... 12)

主要處理顯示邏輯的程式碼:

const getVisiblePages = ()=>{
// 總頁數小於顯示頁數,直接返回頁數陣列
if(totalPages <= maxVisiblePages){
return Array.from({length: totalPages}, (_,i)=> i+1);
  }

// 計算要顯示的連續數字
const halfVisible = Math.floor(maxVisiblePages/2);
let startPage = Math.max(currentPage-halfVisible , 1);
let endPage = Math.min(startPage + maxVisiblePages-1 , totalPages);
 
// 處理邊界的狀況,如果剩下的顯示頁數少於最大可顯示頁數,將起始往左移
if(endPage - startPage + 1 <maxVisiblePages){
startPage = Math.max(endPage - maxVisiblePages + 1, 1);
}
const pages = [];

// 處理起始部分
if(startPage >1){
pages.push(1);
if(startPage > 2) pages.push("...");
}
// 放入連續頁碼
for (let i = startPage; i<= endPage; i++){
  pages.push(i);
}
// 處理結尾部分
if(endPage < totalPages){
if(endPage < totalPages -1) pages.push("...");
pages.push(totalPages);
}
return pages;
}

顯示邏輯:

const visiblePages = getVisiblePages();
return(
<div className="btn-number-container">
{visiblePages.map((page, index)=>{
  if(page === "..."){
  return( {`...`} )
}
return(
<button
key={`${page}-${index}`}
onClick={()=>onPageChange(page)}
>
{page}
</button>
)
})}
</div>
)

總結

以上就是我的前端分頁實作紀錄~ 透過將資料處理邏輯放在父元件,並將 UI 獨立封裝為子元件,在開發方面,不僅讓程式碼更易於維護,也實現了元件的可重用性。

雖然前端分頁看似簡單,但要做到 UX 友善與邏輯嚴謹仍需注意許多細節,像是我做的第一版並沒有加入省略符號的設計,這樣會讓文章數量變多時使用體驗很差~ 不過寫程式就是這樣,完成後總會發現可以再優化的地方,這也正是程式開發的樂趣所在~



留言
avatar-img
Elaine 粼粼的林林總總
92會員
44內容數
不定期地分享程式/旅遊/學習/閱讀或各式各樣的文章,如果對我的分享有興趣,歡迎來找我玩~
2026/04/12
本篇文章教學如何利用 i18next 的 Dynamic Loading 功能,將翻譯檔改為非同步載入,有效減少 JavaScript 包裹體積,加快網頁載入速度,並方便進行多語言維護。
2026/04/12
本篇文章教學如何利用 i18next 的 Dynamic Loading 功能,將翻譯檔改為非同步載入,有效減少 JavaScript 包裹體積,加快網頁載入速度,並方便進行多語言維護。
2026/04/05
本篇文章記錄如何結合 react-router-dom 與 i18next,讓網址能自動與網站的語言狀態同步,提升 SEO 並優化使用者體驗,使 URL 成為語言狀態的單一真相來源。
2026/04/05
本篇文章記錄如何結合 react-router-dom 與 i18next,讓網址能自動與網站的語言狀態同步,提升 SEO 並優化使用者體驗,使 URL 成為語言狀態的單一真相來源。
2026/03/28
本文記錄如何在 React 專案中用 i18next、react-i18next 和 i18next-browser-languagedetector 套件實現網站多語系。涵蓋建立翻譯檔、初始化 i18next ,及在 React 元件中使用 useTranslation 進行內容翻譯與語言切換。
2026/03/28
本文記錄如何在 React 專案中用 i18next、react-i18next 和 i18next-browser-languagedetector 套件實現網站多語系。涵蓋建立翻譯檔、初始化 i18next ,及在 React 元件中使用 useTranslation 進行內容翻譯與語言切換。
看更多
你可能也想看
Thumbnail
若說易卜生的《玩偶之家》為 19 世紀的女性,開啟了一扇離家的窄門,那麼《海妲.蓋柏樂》展現的便是門後的窒息世界。本篇文章由劇場演員 Amily 執筆,同為熟稔文本的演員,亦是深刻體察制度縫隙的當代女性,此文所看見的不僅僅是崩壞前夕的最後發聲,更是女人被迫置於冷酷的制度之下,步步陷入無以言說的困境。
Thumbnail
若說易卜生的《玩偶之家》為 19 世紀的女性,開啟了一扇離家的窄門,那麼《海妲.蓋柏樂》展現的便是門後的窒息世界。本篇文章由劇場演員 Amily 執筆,同為熟稔文本的演員,亦是深刻體察制度縫隙的當代女性,此文所看見的不僅僅是崩壞前夕的最後發聲,更是女人被迫置於冷酷的制度之下,步步陷入無以言說的困境。
Thumbnail
長期以來,西方美學以《維特魯威人》式的幾何比例定義「完美身體」,這種視覺標準無形中成為殖民擴張與種族分類的暴力工具。本文透過分析奈及利亞編舞家庫德斯.奧尼奎庫的舞作《轉轉生》,探討當代非洲舞蹈如何跳脫「標本式」的文化觀看。
Thumbnail
長期以來,西方美學以《維特魯威人》式的幾何比例定義「完美身體」,這種視覺標準無形中成為殖民擴張與種族分類的暴力工具。本文透過分析奈及利亞編舞家庫德斯.奧尼奎庫的舞作《轉轉生》,探討當代非洲舞蹈如何跳脫「標本式」的文化觀看。
Thumbnail
這篇文章深入淺出地解釋 JavaScript 中表達式 (expression) 與陳述式 (statement) 的差異,並以 React 中 JSX 的應用為例,說明為何大括號 {} 內只能放入表達式。文章以類比人類語言的句子結構來幫助理解,並提供相關參考資料連結。
Thumbnail
這篇文章深入淺出地解釋 JavaScript 中表達式 (expression) 與陳述式 (statement) 的差異,並以 React 中 JSX 的應用為例,說明為何大括號 {} 內只能放入表達式。文章以類比人類語言的句子結構來幫助理解,並提供相關參考資料連結。
Thumbnail
全新版本的《三便士歌劇》如何不落入「復刻經典」的巢臼,反而利用華麗的秀場視覺,引導觀眾在晚期資本主義的消費愉悅之中,而能驚覺「批判」本身亦可能被收編——而當絞繩升起,這場關於如何生存的黑色遊戲,又將帶領新時代的我們走向何種後現代的自我解構?
Thumbnail
全新版本的《三便士歌劇》如何不落入「復刻經典」的巢臼,反而利用華麗的秀場視覺,引導觀眾在晚期資本主義的消費愉悅之中,而能驚覺「批判」本身亦可能被收編——而當絞繩升起,這場關於如何生存的黑色遊戲,又將帶領新時代的我們走向何種後現代的自我解構?
Thumbnail
本文深度解析賽勒布倫尼科夫的舞臺作品《傳奇:帕拉贊諾夫的十段殘篇》,如何以十段殘篇,結合帕拉贊諾夫的電影美學、象徵意象與當代政治流亡抗爭,探討藝術在儀式消失的現代社會如何承接意義,並展現不羈的自由靈魂。
Thumbnail
本文深度解析賽勒布倫尼科夫的舞臺作品《傳奇:帕拉贊諾夫的十段殘篇》,如何以十段殘篇,結合帕拉贊諾夫的電影美學、象徵意象與當代政治流亡抗爭,探討藝術在儀式消失的現代社會如何承接意義,並展現不羈的自由靈魂。
Thumbnail
這一集用最新的Vite工具去創建初始檔案。Vite用於創建和構建Web應用程序,具有快速的啟動時間、即時熱更新、小型體積、支持多種框架和可擴展性等優點。
Thumbnail
這一集用最新的Vite工具去創建初始檔案。Vite用於創建和構建Web應用程序,具有快速的啟動時間、即時熱更新、小型體積、支持多種框架和可擴展性等優點。
Thumbnail
在 2021 年的剛轉職成為前端工程師的時候,我在面試時滿常會被詢問到 JavaScript 中閉包的議題,當時候自己回答的滿差的,於是在 2022 年時,我寫了一系列的有關於函式程式設計鐵人賽的文章, 裡頭就有簡單提到有關於閉包的議題。
Thumbnail
在 2021 年的剛轉職成為前端工程師的時候,我在面試時滿常會被詢問到 JavaScript 中閉包的議題,當時候自己回答的滿差的,於是在 2022 年時,我寫了一系列的有關於函式程式設計鐵人賽的文章, 裡頭就有簡單提到有關於閉包的議題。
Thumbnail
Storybook 是一個用來透過獨立元件快速開發 UI 介面的工具,以往要開發元件時,我們可能需要建立一個全新的頁面才能進行開發,但這樣的開發方式可能會有一個狀況:沒有辦法事先開發或是預覽流程中不存在的元件。 透過 Storybook 我們在開發元件時,不需要重新建立複雜的頁面結構⋯⋯
Thumbnail
Storybook 是一個用來透過獨立元件快速開發 UI 介面的工具,以往要開發元件時,我們可能需要建立一個全新的頁面才能進行開發,但這樣的開發方式可能會有一個狀況:沒有辦法事先開發或是預覽流程中不存在的元件。 透過 Storybook 我們在開發元件時,不需要重新建立複雜的頁面結構⋯⋯
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News