У меня есть таблица 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