如何在MUI X Data Grid编辑单元格时更新useState中的总计值?
MUI X Data Grid编辑单元格时外部总计值无法更新的解决方法
问题背景
在使用MUI X Data Grid的编辑模式时,允许用户修改qteLivree(已交付数量),每行的prixTotal(小计)能正常计算,但外部展示的总计值无法同步更新。尝试过onCellEditStop无法获取最新值,使用processRowUpdate时更新一行后另一行会恢复初始值。
问题根源
当前代码中rows是直接从commande props生成的静态变量,并非React状态。Data Grid内部编辑行数据后,外部的rows不会同步更新,导致total状态始终基于初始值计算。另外使用processRowUpdate时未正确更新状态中的行数据,才会出现行数据回退的问题。
解决方案
方案一:将rows转为状态,通过processRowUpdate同步更新行数据与总计
把行数据转为React状态,通过processRowUpdate处理编辑后的行数据更新,同时自动重新计算总计值。
修改后的完整代码:
import { DataGrid, GridColDef, GridCellParams, gridClasses, useGridApiRef, GridRowModel } from "@mui/x-data-grid"; import {Box} from "@mui/material"; import * as React from "react"; import {DetailCommande, Ligne} from "../../../../app/models/commande"; import {useState, useEffect} from "react"; type row = { id: number, reference: string | null, qte: number, qteLivree: number, designation: string, prixUnitaire: number, } const TableauValidationBL = ({commande}: { commande: DetailCommande }) => { const apiRef = useGridApiRef() const columns: GridColDef[] = [ {field: 'reference', headerName: 'Référence', width: 120, headerClassName: 'header'}, {field: 'designation', headerName: 'Désignation', flex: 1, headerClassName: 'header'}, { field: 'qteLivree', headerName: 'Qté validé', width: 120, headerClassName: 'header', editable: true, type: 'number' }, {field: 'prixUnitaire', headerName: 'Prix Unitaire', width: 120, headerClassName: 'header'}, { field: 'prixTotal', headerName: 'Prix Total', width: 120, headerClassName: 'header', valueGetter: (_, row) => { return (row.prixUnitaire * row.qteLivree).toFixed(3); } }, ]; // 将rows转为React状态,初始值从commande生成 const [rows, setRows] = useState<row[]>(commande ? commande.lignes.map((ligne: Ligne) => { return { id: ligne.idPackaging, reference: ligne.refFournisseur, qte: ligne.qteCmd, qteLivree: ligne.qteCmd, designation: ligne.nomArticle, prixUnitaire: ligne.prixUnitaire, } }) : [] ); const [total, setTotal] = useState(0); // 监听rows变化,自动重新计算总计 useEffect(() => { const calculatedTotal = rows.reduce((acc, row) => acc + row.prixUnitaire * row.qteLivree, 0); setTotal(calculatedTotal); }, [rows]); // 处理行更新,替换对应id的行数据 const processRowUpdate = (newRow: GridRowModel) => { const updatedRows = rows.map(row => row.id === newRow.id ? {...row, ...newRow} : row); setRows(updatedRows); return newRow; }; return ( <Box sx={{ '.header': {backgroundColor: 'lightgrey', fontSize: '1.2em'}, [`.${gridClasses.cell}.changed`]: { backgroundColor: '#76CDCD', }, [`.${gridClasses.cell}.unchanged`]: { backgroundColor: '#7AA95C', }, }} > <p>{total.toFixed(3)}</p> <DataGrid autoHeight hideFooter getRowHeight={() => 'auto'} rows={rows} columns={columns} apiRef={apiRef} showCellVerticalBorder getCellClassName={(params: GridCellParams) => { if (params.field === 'qteLivree' && params.value !== params.row.qte) { return 'changed'; } if (params.field === 'qteLivree' && params.value === params.row.qte) { return 'unchanged'; } return ''; }} processRowUpdate={processRowUpdate} editMode="row" /> </Box> ); }; export default TableauValidationBL;
关键修改点
- 将
rows转为useState状态,确保行数据变化时触发组件重渲染 - 使用
useEffect监听rows变化,自动重新计算并更新总计值 - 实现
processRowUpdate方法,正确更新状态中的行数据,避免编辑后行数据回退 - 开启
editMode="row"(若需单元格编辑可改为cell模式,processRowUpdate依然生效)
方案二:通过apiRef获取最新行数据计算总计
如果不想维护rows状态,可以直接通过apiRef从Data Grid实例中获取最新行数据,在单元格编辑完成后重新计算总计:
// 省略其他代码... const [total, setTotal] = useState(rows.reduce((acc, row) => acc + row.prixUnitaire * row.qteLivree, 0)); const handleCellEditCommit = () => { // 通过apiRef获取所有行的最新数据 const allRows = apiRef.current.getRows(); const calculatedTotal = allRows.reduce((acc, row) => acc + row.prixUnitaire * row.qteLivree, 0); setTotal(calculatedTotal); }; return ( <Box> <p>{total.toFixed(3)}</p> <DataGrid // 保留原有属性... onCellEditCommit={handleCellEditCommit} /> </Box> );
这种方式无需维护行数据状态,直接从Data Grid内部获取最新数据,适合简单场景。
内容的提问来源于stack exchange,提问作者Fraki
相关产品推荐
相关产品推荐

