React / Redux: рассылка и обновление состояния вопросов / разъяснений - PullRequest
0 голосов
/ 05 сентября 2018

Я использую таблицы Material UI для заполнения таблицы некоторыми данными, взятыми из моего хранилища Redux, а затем использую функцию для удаления данных.

Таблица, которую я использую, находится здесь https://material -ui.com / demos / tables / и помечена как «Сортировка и выбор». Я просто включу интересующую нас часть, а все остальное пропущу.

Поэтому, когда компонент монтируется, я получаю данные из базы данных, отправляя «startGetClients», и передаю данные в состоянии «ClientsListTable», чтобы заполнить таблицу. Это отлично работает.

При нажатии на «div» (это на самом деле Icon в другом компоненте, но для целей тестирования я использовал простой «div»), я беру массив с выбранными идентификаторами и в «forEach» отправляю » removeClients "прохождение объекта. Если я проверяю состояние в Redux dev tool, я вижу, что оно правильно обновлено и объект удален, но я не могу обновить состояние ClientsListTable, пока не нажму снова, несмотря на то, что я запускаю функцию setState (), передавая новые данные , Я знаю, что это как-то связано с ASYNC, но я не могу понять это.

Клиент был удален, но состояние «ClientsListTable» не обновляется, несмотря на тот факт, что я запускаю setState () сразу после

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 голосов
/ 05 сентября 2018

Сложно узнать без дополнительной информации о вашем проекте, но я думаю, что виноват следующий метод:

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

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

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

Здесь вы отправляете событие удаления для каждого идентификатора (асинхронно), а затем, когда вы закончите, вы явно устанавливаете state = data. Проблема здесь в том, «что это за данные на данный момент?» Я подозреваю, что в первый раз, когда вы вызываете это, он устанавливает его, используя «данные», а когда вы вызываете его снова, он устанавливает его, используя «новые данные» из хранилища редуксов.

Если вы измените это так, чтобы оно зависело от хранилища: 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

Просто удалите вызов setState в вашем методе handleDeletedData. Когда приставка обновляет хранилище, ваши свойства должны измениться и заставить таблицу отображаться.

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

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

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