MUI DataGrid通过QuickSearchToolbar调用外部API实现服务端筛选
解决MUI DataGrid基于外部API的服务端快速筛选问题
核心问题分析
- 状态定义错误:
searchInput状态声明在组件外部,既违反React状态管理规则,也无法在App组件与QuickSearchToolbar之间共享状态。 - 组件通信缺失:自定义Toolbar组件未接收父组件的状态更新方法,无法将搜索输入值同步到App组件。
- Effect依赖不全:数据请求的
useEffect未监听searchInput变化,导致搜索输入改变时不会触发API请求刷新数据。 - 分页逻辑冲突:初始
page值设为0,结合DataGrid的page={pageState.page - 1}会导致分页参数异常(API请求page=0,而DataGrid显示page=-1)。 - total字段误用:DataGrid的
rowCount需要总数据条数,原代码使用totalPages(总页数)会导致分页控件显示错误。
修复后的完整代码
import { Box, Container } from "@mui/material"; import { DataGrid, GridToolbarQuickFilter } from "@mui/x-data-grid"; import { useEffect, useState } from "react"; import { BASE_URL } from "../services/urls"; import jwtInterceptor from "../components/shared/jwtInterceptor"; // 自定义Toolbar,通过props接收搜索状态与更新方法 const QuickSearchToolbar = ({ searchInput, setSearchInput }) => { return ( <Box sx={{ p: 0.5, pb: 0 }}> <GridToolbarQuickFilter value={searchInput} onChange={(e) => setSearchInput(e.target.value)} placeholder="جستجو در نام شرکت..." /> </Box> ); }; function App() { const [pageState, setPageState] = useState({ isLoading: false, data: [], total: 0, page: 1, // 初始page设为1,匹配API分页逻辑(假设API从1开始计数) pageSize: 5, }); // 将搜索状态移到App组件内部 const [searchInput, setSearchInput] = useState(""); const [columns] = useState([ { field: "id", headerName: "شناسه", flex: 1, minWidth: 120, }, { field: "httpMethod", headerName: "متد درخواست", flex: 1, minWidth: 150, }, { field: "createdBy", headerName: "نام شرکت", flex: 1, minWidth: 150, }, { field: "uri", headerName: "آدرس یو آر ال", flex: 1, minWidth: 500, }, { field: "responseBody", headerName: "بدنه پاسخ", flex: 1, minWidth: 600, }, { field: "requestBody", headerName: "بدنه درخواست", flex: 1, minWidth: 400, }, { field: "requestHeader", headerName: "هدر درخواست", flex: 1, minWidth: 400, }, { field: "responseHeader", headerName: "هدر پاسخ", flex: 1, minWidth: 400, }, { field: "requestTime", headerName: "زمان درخواست" }, { field: "responseTime", headerName: "زمان پاسخ", }, { field: "responseStatus", headerName: "وضعیت پاسخ", }, { field: "responseException", headerName: "خطا", }, { field: "createdAt", headerName: "زمان ایجاد" }, { field: "updatedAt", headerName: "زمان بروز رسانی" }, { field: "updatedBy", headerName: "کاربر بروز رسانی" }, ]); useEffect(() => { const fetchData = async () => { setPageState(old => ({ ...old, isLoading: true })); try { const response = await jwtInterceptor.post( `${BASE_URL}log/thirdPartyServices/filter?page=${pageState.page}&size=${pageState.pageSize}`, { httpMethod: "POST", createdBy: searchInput || null, // 空输入时传递null,符合后端参数预期 uri: null, responseException: null, responseStatus: null, } ); setPageState(old => ({ ...old, isLoading: false, data: response.data.content, total: response.data.totalElements, // 使用总条数作为rowCount的数据源 })); } catch (err) { console.error("دریافت دادهها با خطا مواجه شد:", err); setPageState(old => ({ ...old, isLoading: false })); } }; fetchData(); }, [pageState.page, pageState.pageSize, searchInput]); // 添加searchInput到依赖数组,触发搜索时的请求 return ( <Box> <Container style={{ marginTop: 100, marginBottom: 100 }}> <DataGrid autoHeight rows={pageState.data} rowCount={pageState.total} loading={pageState.isLoading} rowsPerPageOptions={[10, 30, 50, 70, 100]} pagination page={pageState.page - 1} // DataGrid的page从0开始,对应API的page从1开始 pageSize={pageState.pageSize} paginationMode="server" onPageChange={(newPage) => { setPageState(old => ({ ...old, page: newPage + 1 })); }} onPageSizeChange={(newPageSize) => setPageState(old => ({ ...old, pageSize: newPageSize, page: 1 })) // 切换每页条数时重置到第一页 } columns={columns} components={{ Toolbar: () => <QuickSearchToolbar searchInput={searchInput} setSearchInput={setSearchInput} /> }} /> </Container> </Box> ); } export default App;
关键优化点说明
- 状态管理修正:将
searchInput移到App组件内部,通过props传递给Toolbar,实现父子组件状态同步。 - 搜索控件绑定:使用
value和onChange替代错误的quickFilterParser,正确捕获搜索输入值。 - 依赖数组完善:添加
searchInput到useEffect依赖,确保搜索输入变化时自动触发API请求。 - 分页逻辑统一:初始
page设为1,配合DataGrid的page={pageState.page - 1},保证前后端分页参数匹配。 - 错误处理:添加
try/catch捕获API请求异常,避免页面一直处于加载状态。 - 分页重置:切换每页条数时自动重置到第一页,避免出现无数据的页码。
内容的提问来源于stack exchange,提问作者Kasra Roshan
相关产品推荐
相关产品推荐

