Невозможно добавлять, обновлять, удалять строки в таблице материалов, реагировать с использованием компонента на основе классов. Раньше работал с функциональной составляющей.

Я не могу добавлять, обновлять или удалять строки в таблице материалов. Если я инициализирую данные в состоянии, он просто отображает их, но не могу их редактировать или удалять, и я не могу добавлять данные в таблицу. Введенные в таблицу данные также отражаются в состоянии, но когда компонент повторно отрисовывается после setState, он не отображается в таблице.

Код, приведенный на официальном сайте, также ведет себя так же, как мой. ссылка на пример на официальном сайте: https://material-table.com/#/docs/features/editable

Я создал codeandbox для referal: https://codesandbox.io/s/material-demo-pqq3t?fontsize=14&hidenavigation=1&module=%2Fdemo.js&theme=dark

Одна вещь, которую я не могу понять, это то, что когда я инициализирую данные для состояния, к данным добавляется одно новое свойство, то есть tableData. Но когда я добавляю данные в состоянии из таблицы, это свойство не устанавливается для этих объектов введите описание изображения здесь
Это мой код: `

state = {
    openDialog: false,
    nameOfCustomer: "",
    date: new Date(),
    items: [{ item: 'Mehmet', cost: 10, quantity: 7, total: null }],
    tax: 0,
    total: 0,
    roundoff: 0,
    columns: [
        { title: 'Item', field: 'item', },
        { title: 'Quantity', field: 'quantity', type: 'numeric', },
        { title: 'Cost/Item', field: 'cost', type: 'numeric', },
        { title: 'Total', field: 'total', type: 'numeric', editable: 'never' },
    ],
}

// componentDidUpdate(){
//     // console.log(this.props.invoices)
// }

handleClose = () => {
    this.setState({ openDialog: false })
}

feedDataIntoStore = () => {
    const { nameOfCustomer, date, items } = this.state;
    const storeData = { nameOfCustomer, date, items };
    if (!nameOfCustomer || items.length === 0 || !date) this.setState({ openDialog: true });
    // console.log(storeData);
    this.props.dispatch(createInvoice(storeData));
}

handleItemListData = (data) => {
    this.setState({ items: data.items, total: data.total, tax: data.tax, roundoff: data.roundoff })
}

handleNameChange = (e) => {
    this.setState({ nameOfCustomer: e.target.value })
}

handleDateChange = newDate => {
    this.setState({
        date: newDate
    })
};
render() {
    const { classes } = this.props;
    return (<React.Fragment>
        <Container>
            <Paper className={classes.root}>

                <Typography variant="h5" component="h3">
                    Create Invoice
                </Typography>

                <Divider style={{ marginTop: 15, marginBottom: 15 }} />

                <TextField
                    id="standard-full-width"
                    label="Name"
                    style={{ margin: 8 }}
                    placeholder="Name of Customer"
                    margin="normal"
                    fullWidth
                    value={this.state.nameOfCustomer}
                    onChange={this.handleNameChange}
                    InputLabelProps={{
                        shrink: true,
                    }}
                />

                <MuiPickersUtilsProvider utils={DateFnsUtils}>
                    <KeyboardDatePicker
                        style={{ margin: 8, marginBottom: 20 }}
                        margin="normal"
                        id="date-picker-dialog"
                        label="Date picker dialog"
                        format="dd/MM/yyyy"
                        value={this.state.date}
                        onChange={this.handleDateChange}
                        KeyboardButtonProps={{
                            'aria-label': 'change date',
                        }}
                />
                </MuiPickersUtilsProvider>
                {console.log(this.state.items)}
                <MaterialTable
                    title="Items"
                    enableRowDelete={true}
                    enableRowAdd={true}
                    columns={this.state.columns}
                    data={this.state.items}
                    editable={{
                        onRowAdd: newData =>
                            new Promise(resolve => {
                                setTimeout(() => {
                                    resolve();
                                    const newItems = this.state.items;
                                    if (!newData.cost || !newData.quantity) {
                                        this.setState({dialogOpen: true });
                                        // handleDateChange({ items: state.items, total, tax, roundoff });
                                    }
                                    else {
                                        let newtotal = 0, newtax = 0, newroundoff = 0;
                                        newData.total = parseFloat((newData.cost * newData.quantity).toFixed(2));
                                        newItems.push(newData);
                                        newItems.forEach((item) => { newtotal = newtotal + parseFloat(item.total, 10) });
                                        newtotal.toFixed(2);
                                        newtax = parseFloat(((newtotal / 100) * 28).toFixed(2));
                                        newroundoff = parseFloat((Math.round(newtotal + newtax) - (newtotal + newtax)).toFixed(2));
                                        newtotal = parseInt(Math.round(newtotal + newtax));
                                        this.setState({ items: newItems, tax: newtax, roundoff: newroundoff, total: newtotal });
                                    }
                                }, 500);
                            }),
                        onRowUpdate: (newData, oldData) =>
                            new Promise(resolve => {
                                setTimeout(() => {
                                    resolve();
                                    if (oldData) {
                                        const newItems = this.state.items;
                                        if(!newData.cost || !newData.quantity) 
                                        this.setState({dialogOpen: true})
                                        else{    
                                            let newtotal = 0, newtax = 0, newroundoff = 0;
                                            newData.total = parseFloat((newData.cost * newData.quantity).toFixed(2));
                                            newItems[newItems.indexOf(oldData)] = newData;
                                            newItems.forEach((item) => { newtotal = newtotal + parseFloat(item.total, 10) });
                                            newtotal.toFixed(2);
                                            newtax = parseFloat(((newtotal / 100) * 28).toFixed(2));
                                            newroundoff = parseFloat((Math.round(newtotal + newtax) - (newtotal + newtax)).toFixed(2));
                                            newtotal = parseInt(Math.round(newtotal + newtax));
                                            this.setState({ items: newItems, tax: newtax, roundoff: newroundoff, total: newtotal });
                                        }
                                    }
                                }, 500);
                            }),
                            onRowDelete: oldData =>
                            new Promise(resolve => {
                                setTimeout(() => {
                                    resolve();
                                        const newItems = this.state.items;
                                        let newtotal = 0, newtax = 0, newroundoff = 0;
                                        newItems.splice(newItems.indexOf(oldData), 1);
                                        newItems.forEach((item) => { newtotal = newtotal + parseFloat(item.total, 10) });
                                        newtotal.toFixed(2);
                                        newtax = parseFloat(((newtotal / 100) * 28).toFixed(2));
                                        newroundoff = parseFloat((Math.round(newtotal + newtax) - (newtotal + newtax)).toFixed(2));
                                        newtotal = parseInt(Math.round(newtotal + newtax));
                                        this.setState({ items: newItems, tax: newtax, roundoff: newroundoff, total: newtotal });
                                }, 500);
                            }),
                    }}
                    options={{
                        rowStyle: {
                            backgroundColor: '#EEE',
                        },
                        actionsColumnIndex: 3,
                        search: false,
                        minBodyHeight: 300,
                        loadingType: "linear",
                    }}
                    components={{
                        Cell: props => (
                            <MTableCell {...props} className={classes.noBorder} />
                        ),
                        EditField: props => (
                            <MTableEditField {...props} className={classes.customWidth} />
                        ),
                        Pagination: props => (
                            <TableCell colSpan={3} className={classes.footerFix}>
                                <Box component="span" m={1} className={classes.flex}>
                                    <Typography variant="h6" component="span" align={"center"}>Tax Amount: </Typography>
                                    <Typography variant="h6" component="span" align={"center"}>{this.state.tax}</Typography>
                                </Box>
                                <Divider variant="middle" />
                                <Box component="span" m={1} className={classes.flex}>
                                    <Typography variant="h5" component="span" align={"center"}>Total Amount: </Typography>
                                    <span style={{ display: "flex", flexDirection: "column", height: "3em", alignItems: "flex-end" }}>
                                        <Typography variant="button" component="span" align={"center"}><span>Round off.</span> <span>{this.state.roundoff}</span></Typography>
                                        <Typography variant="h5" component="span" align={"center"}>{this.state.total}</Typography>
                                    </span>
                                </Box>
                            </TableCell>
                        ),
                    }}
                />

                <DisableFieldEditable />
                <AlertDialog text = {"Please Enter All Data....."} title = {"Invalid Input"} open = {this.state.openDialog} handleClose = {this.handleClose}/>

                <Button variant="contained" color="primary" className={classes.button} onClick={this.feedDataIntoStore}>
                    Create Invoice
                </Button>
            </Paper>
        </Container>
                <AlertDialog text={"You Need To Provide All The Data To Create Invoice, Fields Can't Be Kept Empty"} title={"Can't Create Invoice"} open={this.state.openDialog} handleClose={this.handleClose} />
    </React.Fragment>);
}

`


person Bhushan Dangore    schedule 24.12.2019    source источник


Ответы (2)


Ответ Domino987 почти правильный. Единственная проблема заключается в том, что при обновлении строки добавляется новая строка. Итак, мое решение:

                         onRowUpdate: (newData, oldData) =>
                         new Promise((resolve, reject) => {
                             setTimeout(() => {
                               let clone = [];
                               Object.assign(clone, this.state.data);
                               console.log("clone1:", clone);
                               const index = this.state.data.indexOf(oldData);
                               clone[index] = newData;
                               this.setState({ data:clone }, () => {
                                 resolve();
                               });
                             }, 1000);
                           }),

Предупреждение: Object.assign может быть неподходящим методом клонирования в зависимости от вашей структуры данных.

person GCab    schedule 09.01.2020
comment
Спасибо, это сделало мой день лучше! - person Daniele; 25.03.2020

Вы изменяете объект данных в состоянии вместо того, чтобы обновлять его неизменяемым.

Из-за этого response пропустит повторную визуализацию, и новые данные не будут переданы в таблицу. Если ссылки на все объекты в штате такие же, как и раньше, response выйдет из строя раньше. Создавая новый объект с data: [...data, newData], вы изменяете ссылку на объект данных, и react будет правильно перерисовывать.

Измените его на это, и он работает:

new Promise((resolve, reject) => {
          setTimeout(() => {
            this.setState(prevState => ({
              data: [...prevState.data, newData]
            }), resolve);
          }, 1000);
        })

Это просто пример кода для onRowAdd, который необходимо изменить для onRowUpdate и onRowDelete. Но это общая идея.

Это также применимо к хуку useState, который будет следующим образом:

const [data, setData] = useState([]);
...

setData(prevData => [...prevData, newData])
person Domino987    schedule 27.12.2019
comment
Этот ответ помог мне решить возникшую у меня проблему. Я пытался нажать на массив, но, вернув новый массив, я смог увидеть обновление страницы. - person Scott; 08.03.2020
comment
Это тоже сделало мой день! Спасибо! - person Daniele; 25.03.2020