React / Redux:调度和更新状态问题/说明

时间:2018-09-05 14:33:35

标签: reactjs asynchronous redux es6-promise

我正在使用Material UI表用从Redux存储中获取的一些数据填充表,然后使用函数删除数据。

我正在使用的表在https://material-ui.com/demos/tables/上,是标记为“排序并选择”的表。我将只包括我们感兴趣的部分,并省略所有其余部分。

因此,在安装组件时,我通过调度“ startGetClients”从数据库中获取数据,并以“ ClientsListTable”状态传递数据以填充表。效果很好。

点击删除的“ div”(实际上是另一个组件中的Icon,但是出于测试目的,我使用了一个简单的“ div”),我选择了具有选定ID的数组,并在“ forEach”中分配了“ removeClients”传递对象。如果我在Redux开发工具上检查状态,我可以看到它已正确更新并且该对象已删除,但是我无法更新ClientsListTable的状态,除非我再次单击,尽管我运行了setState()函数并传递了新数据。我知道它与ASYNC有关,但我无法弄清楚。

Client has been removed but the state of "ClientsListTable" is not updated despite the fact that I am running setState() immediately after

class ClientsListTable extends Component {

  constructor(props) {
    super(props);

    this.state = {
      order: 'asc',
      orderBy: 'name',
      selected: [],
      data: [],
      page: 0,
      rowsPerPage: 5,
    };
  }

  componentWillMount() {
    this.props.startGetClients().then(() => {
      let data = this.props.clients;
      this.setState( () =>({ data }) );
    });
  }

  handleSelectAllClick = (event, checked) => {
    if (checked) {
      this.setState(state => ({ selected: state.data.map(n => n.id) }));
      return;
    }
    this.setState({ selected: [] });
  };

  handleDeletedData = (selectedIds, data) => {
    selectedIds = this.state.selected;
    data = this.props.clients;

    selectedIds.forEach(id => {
      this.props.removeClients({id: id});
    });

    this.setState( () =>({ data }) );
  }


  render() {
    const { classes } = this.props;
    const { data, order, orderBy, selected, rowsPerPage, page } = this.state;
    const emptyRows = rowsPerPage - Math.min(rowsPerPage, data.length - page * rowsPerPage);

    return (
      <Paper className={classes.root}>

        <div onClick={this.handleDeletedData}>REMOVE ITEMS</div>

        <ClientsListTableToolbar numSelected={selected.length} selectedId={selected} />
        <div className={classes.tableWrapper}>
          <Table className={classes.table} aria-labelledby="tableTitle">
            <ClientsListTableHead
              numSelected={selected.length}
              order={order}
              orderBy={orderBy}
              onSelectAllClick={this.handleSelectAllClick}
              onRequestSort={this.handleRequestSort}
              rowCount={data.length}
            />
            <TableBody>
              {data
                .sort(getSorting(order, orderBy))
                .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
                .map(n => {
                  const isSelected = this.isSelected(n.id);
                  return (
                    <TableRow
                      hover
                      onClick={event => this.handleClick(event, n.id)}
                      role="checkbox"
                      aria-checked={isSelected}
                      tabIndex={-1}
                      key={n.id}
                      selected={isSelected}
                    >
                      <TableCell padding="checkbox">
                        <Checkbox checked={isSelected} />
                      </TableCell>
                      <TableCell component="th" scope="row" padding="none">
                        {n.clientName}
                      </TableCell>
                      <TableCell>{n.lastLogin ? n.lastLogin : 'Never logged in'}</TableCell>
                    </TableRow>
                  );
                })}
              {emptyRows > 0 && (
                <TableRow style={{ height: 49 * emptyRows }}>
                  <TableCell colSpan={6} />
                </TableRow>
              )}
            </TableBody>
          </Table>
        </div>
        <TablePagination
          component="div"
          count={data.length}
          rowsPerPage={rowsPerPage}
          page={page}
          backIconButtonProps={{
            'aria-label': 'Previous Page',
          }}
          nextIconButtonProps={{
            'aria-label': 'Next Page',
          }}
          onChangePage={this.handleChangePage}
          onChangeRowsPerPage={this.handleChangeRowsPerPage}
        />
      </Paper>
    );
  }

}

const mapStateToProps = (state) => ({
  clients: state.clients,
});

const mapDispatchToProps = (dispatch) => ({
  startGetClients: () => dispatch(startGetClients()),
  removeClients: (data) => dispatch(removeClients(data))
});

export default compose(
  withStyles(styles),
  connect(mapStateToProps,mapDispatchToProps),
)(ClientsListTable);

//动作

export const removeClients = ({ id } = {}) => ({
  type: 'REMOVE_CLIENTS',
  id
});

//减速器

case 'REMOVE_CLIENTS':
  return state.filter( ({id}) => id !== action.id);

1 个答案:

答案 0 :(得分:0)

如果没有有关您的项目的更多信息,很难知道,但我认为可能是以下方法引起的:

handleDeletedData = (selectedIds, data) => {
    selectedIds = this.state.selected;
    data = this.props.clients;

    selectedIds.forEach(id => {
      this.props.removeClients({id: id});
    });

    this.setState( () =>({ data }) );
  }

您在这里所做的是(异步)为每个ID调度一个remove事件,然后在完成后显式设置state = data。这里的问题是“此时的数据是什么?”我怀疑您第一次调用它时会使用“数据”来设置它,而当您再次调用它时,它会使用redux存储中的“新数据”来设置它。

如果您对此进行更改以使其取决于存储:this.props.clients而不是状态:this.state.data,则它应该在化简版更新存储时进行更新。

尝试一下,而不是:

const { classes } = this.props;
const { data, order, orderBy, selected, rowsPerPage, page } = this.state;

尝试

const { classes } = this.props;
const { order, orderBy, selected, rowsPerPage, page } = this.state;
const data = this.props.clients

只需在您的handleDeletedData方法中删除“ setState”调用即可。当redux更新商店时,您的属性应更改并强制表呈现。

handleDeletedData = (selectedIds, data) => {
    selectedIds = this.state.selected;
    data = this.props.clients;

    selectedIds.forEach(id => {
      this.props.removeClients({id: id});
    });

//    this.setState( () =>({ data }) );
  }