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

material-react-table分页按钮禁用,排序搜索正常求助

Material-React-Table分页按钮禁用问题排查与解决

问题描述

使用material-react-table库从API获取数据,排序和搜索功能正常,但分页按钮处于禁用状态,导致分页功能完全失效。

相关代码

ProductReviews组件代码

import { useMemo, useState } from "react";
import {
  MaterialReactTable,
  type MRT_ColumnDef,
  type MRT_PaginationState,
  type MRT_SortingState,
} from "material-react-table";
import {
  IconButton,
  MenuItem,
  Tooltip,
  ListItemIcon,
  Typography,
  Rating,
} from "@mui/material";
import RefreshIcon from "@mui/icons-material/Refresh";
import DeleteIcon from "@mui/icons-material/Delete";
import DeleteModal from "../../../components/admin/modals/DeleteModal";
import useTableQueryHook from "../../../hooks/useTableQueryHook";
import {Link as RouterLink} from "react-router-dom"
import Link from "@mui/material/Link";


type Props = {
    id:string
}    

const ProductReviews = ({id}: Props) => {

 
   const [globalFilter, setGlobalFilter] = useState("");
   const [sorting, setSorting] = useState<MRT_SortingState>([]);
   const [pagination, setPagination] = useState<MRT_PaginationState>({
     pageIndex: 1,
     pageSize: 10,
   });
   const {
     data: cateegories,
     isError,
     isRefetching,
     isLoading,
     refetch,
   } = useTableQueryHook({
     sorting,
     globalFilter,
     pagination,
     url: `review/${id}`,
     selectedProp: "reviews",
     queryName: "getReviews",
   });

    const columns = useMemo<MRT_ColumnDef<RivewsListType>[]>(
      () => [
        // columns here
      ],
      []
    );
   const [openDelete, setOpenDelete] = useState(false);
   const [idToDelete, setIdToDelete] = useState("");
  return <>
    <MaterialReactTable
      columns={columns}
      data={cateegories ?? []}
      manualPagination
      enablePagination
      manualSorting
      enableRowActions
      renderRowActionMenuItems={({ closeMenu, row }) => [
        <MenuItem
          key={1}
          onClick={() => {
            setIdToDelete(row.original._id);
            setOpenDelete(true);
            closeMenu();
          }}
          sx={{ m: 0, color: "red" }}
        >
          <ListItemIcon>
            <DeleteIcon sx={{ color: "red" }} />
          </ListItemIcon>
          Delete
        </MenuItem>,
      ]}
      muiToolbarAlertBannerProps={
        isError
          ? {
              color: "error",
              children: "Error loading data",
            }
          : undefined
      }
      onGlobalFilterChange={setGlobalFilter}
      onPaginationChange={setPagination}
      onSortingChange={setSorting}
      renderTopToolbarCustomActions={() => (
        <Tooltip arrow title="Refresh Data">
          <IconButton onClick={() => refetch()}>
            <RefreshIcon />
          </IconButton>
        </Tooltip>
      )}
      state={{
        globalFilter,
        isLoading,
        pagination,
        showAlertBanner: isError,
        showProgressBars: isRefetching,
        sorting,
      }}
    />
    
      </>
  
}

export default ProductReviews

useTableQueryHook钩子代码

import { useQuery, keepPreviousData } from "@tanstack/react-query";
import {
  type MRT_PaginationState,
  type MRT_SortingState,
} from "material-react-table";
import fetchData from "../utils/fetchData";
type Props = {
  sorting: MRT_SortingState;
  globalFilter: string;
  pagination: MRT_PaginationState;
  url:string;
  selectedProp?:string;
  queryName:string
};

const useTableQueryHook = ({
  sorting,
  globalFilter,
  pagination,
  url,
  selectedProp,
  queryName
}: Props) => {
  return useQuery({
    queryKey: [
      queryName,
      globalFilter,
      pagination.pageIndex,
      pagination.pageSize,
      sorting,
    ],
    queryFn: async () => {
      const res: any = await fetchData({
        url: `/${url}?page=${pagination.pageIndex}&size=${
          pagination.pageSize
        }&search=${globalFilter ? globalFilter : ""}&sort=${sorting
          .map((s) => `${s.desc ? "-" : ""}${s.id}`)
          .join(",")}`,
        method: "GET",
        token: localStorage.getItem("token") || "",
      });
      return selectedProp&&res.data[selectedProp] || res.data;
    },
    refetchOnWindowFocus: false,
    refetchOnMount: false,
    placeholderData: keepPreviousData,
    staleTime: 300000,
  });
};

export default useTableQueryHook;

问题排查与解决

1. 分页索引起始值不匹配

Material-React-Table的pageIndex默认从0开始计数,但你的初始状态设置为pageIndex:1,且直接将该值传给后端。如果后端分页逻辑是从1开始,需要调整前端状态或请求参数:

  • 方案一:修改前端初始分页状态为0起始
const [pagination, setPagination] = useState<MRT_PaginationState>({
  pageIndex: 0, // 改为0
  pageSize: 10,
});

同时在请求后端时将pageIndex加1:

url: `/${url}?page=${pagination.pageIndex + 1}&size=${pagination.pageSize}&...`
  • 方案二:如果后端支持0起始分页,直接保持前端pageIndex为0即可。

2. 缺少总数据量(rowCount)传递

开启manualPagination后,表格需要知道总数据条数才能计算分页按钮的可用状态。当前代码只传递了当前页的数据,表格无法判断是否存在下一页/上一页,因此禁用了分页按钮。

解决步骤:

  1. 调整API返回结构,包含总数据条数(比如添加total字段)
  2. 修改useTableQueryHook,返回数据和总条数:
// useTableQueryHook的queryFn中修改返回
return {
  list: selectedProp ? res.data[selectedProp] : res.data,
  total: res.data.total, // 假设后端返回total字段
};
  1. 在ProductReviews组件中接收并传递给表格:
const {
  data: { list: cateegories, total },
  isError,
  isRefetching,
  isLoading,
  refetch,
} = useTableQueryHook(...);

// 给MaterialReactTable添加rowCount属性
<MaterialReactTable
  ...
  rowCount={total}
  ...
/>

3. 验证状态同步

确保onPaginationChange正确更新pagination状态,且react-query的queryKey包含pagination.pageIndex和pagination.pageSize(你的代码已经包含,这部分无需修改),确保分页变化时能触发新的API请求。

内容的提问来源于stack exchange,提问作者Mahmoud Walid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 07:47:12