如何实现基于Laravel API分页的可复用Shadcn Data Table?
解决Shadcn Data Table结合Laravel API服务端分页问题
核心问题
Shadcn的Data Table默认采用客户端分页,会根据传入的data数组长度自动计算分页逻辑。但你用的是Laravel API提供的服务端分页,此时data仅为当前页的数据,总条数是API返回的total字段,默认逻辑会因为data长度不足导致分页失效。
解决步骤
1. 切换为服务端分页模式
需要开启表格的手动分页,让Laravel API负责数据切片,表格仅处理分页UI交互和状态同步。
2. 维护分页与筛选状态
在父组件中管理分页、筛选相关状态,并在状态变化时重新请求API:
import { useState, useCallback, useEffect } from 'react'; const PaymentsTable = () => { // 分页状态(与Laravel API的1-based页码保持一致) const [page, setPage] = useState(1); const [perPage, setPerPage] = useState(15); // 对应API返回的per_page // 数据状态 const [data, setData] = useState([]); const [total, setTotal] = useState(0); // 筛选状态 const [searchQuery, setSearchQuery] = useState(''); const [roleFilter, setRoleFilter] = useState(''); // 请求数据:分页/筛选变化时触发 const fetchData = useCallback(async () => { const params = new URLSearchParams({ page, per_page: perPage, ...(searchQuery && { name: searchQuery }), ...(roleFilter && { role: roleFilter }), }); try { const response = await fetch(`/api/payments?${params}`); const result = await response.json(); setData(result.data); // API返回的当前页数据 setTotal(result.total); // API返回的总数据条数 } catch (err) { console.error('数据请求失败:', err); } }, [page, perPage, searchQuery, roleFilter]); // 初始化/状态变更时请求数据 useEffect(() => { fetchData(); }, [fetchData]); // 重置筛选条件 const resetFilters = () => { setSearchQuery(''); setRoleFilter(''); setPage(1); // 重置后回到第一页 }; const isAnyFilterActive = searchQuery || roleFilter; return ( <div> <div className='flex flex-wrap items-center gap-4'> <DataTableSearch searchKey='name' searchQuery={searchQuery} setSearchQuery={setSearchQuery} setPage={setPage} /> <DataTableFilterBox filterKey='role' title='Role' options={ROLE_OPTIONS} setFilterValue={setRoleFilter} filterValue={roleFilter} /> <DataTableResetFilter isFilterActive={isAnyFilterActive} onReset={resetFilters} /> </div> <DataTable columns={columns} data={data} // 开启手动分页 manualPagination // 计算总页数(向上取整) pageCount={Math.ceil(total / perPage)} // 分页切换回调(保持1-based页码适配Laravel) onPageChange={(newPage) => setPage(newPage)} // 每页条数切换回调 onPerPageChange={(newPerPage) => { setPerPage(newPerPage); setPage(1); // 切换条数后回到第一页 }} currentPage={page} pageSize={perPage} /> </div> ); };
3. 改造DataTable组件适配手动分页
如果是自定义封装的DataTable,需要将分页参数传递给TanStack Table(注意TanStack用0-based索引,需转换为1-based适配Laravel):
import { useTable, usePagination } from '@tanstack/react-table'; const DataTable = ({ columns, data, manualPagination, pageCount, onPageChange, onPerPageChange, currentPage, pageSize, }) => { const table = useTable({ columns, data, manualPagination, pageCount, initialState: { pageIndex: currentPage - 1, // 转成TanStack的0-based索引 pageSize, }, onPageChange: ({ pageIndex }) => onPageChange(pageIndex + 1), // 转回1-based给API onPageSizeChange: (newPageSize) => onPerPageChange(newPageSize), }, usePagination); // 表格渲染、分页器渲染逻辑... };
关键注意事项
- Laravel API用1-based页码,TanStack Table默认用0-based索引,需要在回调中做转换
- 筛选条件或每页条数变化时,必须重置页码为1,避免出现空数据页
- 必须传递
pageCount(总页数)给表格,确保分页组件正确显示页码范围
内容的提问来源于stack exchange,提问作者Raphael Fadimu
相关产品推荐
相关产品推荐

