React多行表格单行Transfer字段独立计算Total及实现Grand Total的技术问询
解决React Row Details组件的行独立计算与汇总问题
嘿,我看了你代码里的问题,核心是全局状态共享导致所有行联动,还有初始值处理不当引发的NaN,咱们一步步搞定它!
问题根源拆解
- 你用了全局的
transfer和total状态,所有行都绑定同一个值,改一行当然全变 - 初始值没做数值转换,输入空值或非数字时会出现NaN
- Grand Total直接用全局total,没法汇总各行的独立计算结果
完整解决方案代码
import React, { useState, useMemo } from 'react'; import Dialog from '@mui/material/Dialog'; import Transition from '@mui/material/Transition'; export default function RowDetails({ open, handleClose, data }) { const { Rate, Stock } = data; // 把每行数据作为独立状态,每行自己管理Transfer和Total const [rows, setRows] = useState([ { id: 1, Lot: "2101000134", Bill: "M0000013092", Shelf: "W13-A1", Bin: "B01", Rate, Stock, Transfer: 0, Total: 0 }, { id: 2, Lot: "2101000134", Bill: "M0000013092", Shelf: "W13-A1", Bin: "B01", Rate, Stock, Transfer: 0, Total: 0 }, ]); // 计算Grand Total,用useMemo优化性能,只在rows变化时重新计算 const grandTotal = useMemo(() => { return rows.reduce((sum, row) => sum + row.Total, 0); }, [rows]); // 精准更新单行数据,避免全局联动 const handleTransferChange = (e, rowId) => { // 把输入值转成数字,空值或非数字时设为0,避免NaN const transferValue = Number(e.target.value) || 0; setRows(prevRows => prevRows.map(row => { if (row.id === rowId) { // 只更新当前行的Transfer和计算Total return { ...row, Transfer: transferValue, Total: row.Rate * transferValue }; } return row; }) ); }; const columns = [ { field: "Lot", headerName: "Lot#", width: 200, editable: false }, { field: "Bill", headerName: "Bill#", width: 130, editable: false }, { field: "Shelf", headerName: "Shelf", width: 200, editable: false }, { field: "Bin", headerName: "Bin", width: 200, editable: false }, { field: "Rate", headerName: "Rate", width: 200, editable: false }, { field: "Stock", headerName: "Stock Balance Qty.", width: 200, editable: false }, { field: "Transfer", headerName: "Transfer Qty.", width: 200, editable: true }, { field: "Total", headerName: "Total", width: 200, editable: false }, ]; return ( <div> <Dialog fullScreen open={open} onClose={handleClose} TransitionComponent={Transition}> <div style={{ height: 400, width: "100%" }}> <table className="dataTable"> <thead> <tr> {columns.map((column) => ( <th key={column.headerName}>{column.headerName}</th> ))} </tr> </thead> <tbody> {rows.map((row) => ( <tr key={row.id}> <td>{row.Lot}</td> <td>{row.Bill}</td> <td>{row.Shelf}</td> <td>{row.Bin}</td> <td>{row.Rate}</td> <td>{row.Stock}</td> <td> {/* 绑定当前行的Transfer值,而非全局状态 */} <input type="number" onChange={(e) => handleTransferChange(e, row.id)} value={row.Transfer} /> </td> {/* 显示当前行的Total,而非全局total */} <td>{row.Total}</td> </tr> ))} </tbody> </table> </div> <table className="totalTable"> <thead> <tr> <th>Grand Total</th> {/* 显示汇总后的Grand Total */} <th>{grandTotal}</th> </tr> </thead> </table> </Dialog> </div> ); }
关键优化点说明
- 行数据独立管理:把每行的
Transfer和Total都放进rows状态数组,每行数据完全独立,修改某一行不会影响其他行 - 数值转换防NaN:在
handleTransferChange里把输入值转成数字,空值或非数字时设为0,彻底避免NaN问题 - Grand Total实时汇总:用
useMemo监听rows变化,实时计算所有行Total的总和,既保证准确性又优化性能 - 移除冗余全局状态:删掉了原来的
transfer和total全局变量,不再需要多余的useEffect
内容的提问来源于stack exchange,提问作者buzz
相关产品推荐
相关产品推荐

