首页 > 解决方案 > Material-ui 可编辑表格单元格,带有货币掩码和表格页脚用于总计

问题描述

我有一个Material-ui必须可编辑的表,每个字段都必须有一个货币掩码,并且该表有一个页脚,用于对每列的行值求和。

我想在输入单元格时更新表格页脚总数。

问题是:要在输入单元格时更新表格页脚总数,我必须执行setState强制重新渲染组件的操作,并且我在该字段中失去焦点并且无法再编辑。

const InputCurrency = ({ value, onChange }) => {
  return (
    <CurrencyTextField
      currencySymbol="€"
      decimalCharacter=","
      digitGroupSeparator=" "
      value={value}
      onChange={onChange}
    />
  );
};
const tableTotalSum = tableData => {
  return tableData.reduce((sum, row) => sum + (row.total ? row.total : 0), 0);
};
const tableTaxSum = tableData => {
  return tableData.reduce((sum, row) => sum + (row.tax ? row.tax : 0), 0);
};
function currencyFormat(num) {
  return `${num.toFixed(2)}`;
}

export default function App() {
  const tableData = [
    {
      total: 100,
      tax: 1
    },
    {
      total: 200,
      tax: 4
    },
    {
      total: 300,
      tax: 33
    },
    {
      total: 400,
      tax: 40
    }
  ];
  const [state, setState] = React.useState(tableData);

  const removeRowHandler = index => () => {
    setState(prevState => {
      const newTableData = [...prevState];
      newTableData.splice(index, 1);
      return newTableData;
    });
  };

  const addRow = () => {
    setState(prevState => {
      const newTableData = [...prevState];
      newTableData.push({});
      //onChangeTableData(newTableData);
      return newTableData;
    });
  };

  const changeValueHandler = (index, value, prop) => {
    setState(prevState => {
      prevState[index][prop] = value;
      return prevState;

      /**
       * TODO this is the problem - If I return [...prevState], this causes
       * a re-render and I loose focus and can't edit.
       * If I just return prevState, it does not cause a re-render,
       * but the total is not updated
       */
      //return [...prevState];
    });
  };

  const TableEditRow = ({ row, index, changeValueHandler }) => {
    const [total, setTotal] = React.useState(row.total ? row.total : "");
    const [tax, setTax] = React.useState(row.tax ? row.tax : "");
    const onChange = (setter, prop) => (event, value) => {
      setter(value);
      changeValueHandler(index, value, prop);
    };

    return (
      <TableRow>
        <TableCell align="right">
          <InputCurrency value={total} onChange={onChange(setTotal, "total")} />
        </TableCell>
        <TableCell align="right">
          <InputCurrency value={tax} onChange={onChange(setTax, "tax")} />
        </TableCell>
        <TableCell align="right" className="MuiTableCell-paddingNone">
          <IconButton aria-label="delete" onClick={removeRowHandler(index)}>
            <DeleteIcon />
          </IconButton>
        </TableCell>
      </TableRow>
    );
  };
  return (
    <div className="App">
      <TableContainer component={Paper}>
        <Table aria-label="spanning table">
          <TableHead>
            <TableRow>
              <TableCell colSpan={2}>
                <h2>Invoice lines</h2>
              </TableCell>
              <TableCell align="right" colSpan={3}>
                <IconButton aria-label="add" onClick={addRow}>
                  <AddBox />
                  Add Line
                </IconButton>
              </TableCell>
            </TableRow>
            <TableRow>
              <TableCell align="right">TOTAL</TableCell>
              <TableCell align="right">TAX</TableCell>
              <TableCell align="right" />
            </TableRow>
          </TableHead>
          <TableBody>
            {state.map((row, index) => (
              <TableEditRow
                key={"TableEditRow" + index}
                row={row}
                index={index}
                changeValueHandler={changeValueHandler}
              />
            ))}
          </TableBody>
          <TableFooter>
            <TableRow>
              <TableCell align="right">
                <span style={{ fontWeight: "bold" }}>
                  Total: {currencyFormat(tableTotalSum(state))}
                </span>
              </TableCell>
              <TableCell align="right">
                <span style={{ fontWeight: "bold" }}>
                  Tax: {currencyFormat(tableTaxSum(state))}
                </span>
              </TableCell>
              <TableCell />
            </TableRow>
          </TableFooter>
        </Table>
      </TableContainer>
    </div>
  );
}

您可以在https://codesandbox.io/s/issue-material-ui-table-footer-totals-tvv1h中尝试此操作

标签: reactjsmaterial-uireact-hooks

解决方案


推荐阅读