You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 00:33:15