Вызов API после setState в React

#javascript #reactjs

#javascript #reactjs

Вопрос:

У меня есть компонент React, который выполняет вызов API с использованием Axios на основе выбранного диапазона дат, который обновляется в состоянии с использованием setState. Я знаю, что поведение setState является асинхронным, поэтому я использовал подход функции стрелки, но безуспешно, состояние компонента не обновляется, в результате вызовы API завершаются неудачно. Ниже приведен фрагмент кода, который я использую:

 class InterfaceDetailsDialog extends React.Component {
  state = {
    fromDate: null,
    toDate: null,
    isForADate: true
  };

  componentDidMount() {
    this.setState({ open: true });
  }

  handleChangeDates = (fromDte, toDte) => {
    console.log("Handle Date Change");
    console.log(fromDte);
    console.log(toDte);
    this.setState(
      {
        isForADate: false,
        fromDate: fromDte,
        toDate: toDte
      },
      () => {
        this.props.onInterfaceStats(
          this.props.data.id,
          this.state.fromDate.format("DD-MM-YYYY"),
          this.state.toDate.format("DD-MM-YYYY")
        );
      }
    );

    console.log("In Set State", this.state.fromDate, ",", this.state.toDate);
  };

  handleSubmit = event => {
    event.preventDefault();
  };

  handleShowTodaysData = () => {
    //   this.props.clearUtilizationForVxc();
    this.setState({ isForADate: true }, this.refreshData);
  };

  renderGraph() {
    if (this.state.isForADate) {
      console.log(this.props.dte);
      return <DetailedChart data={this.props.data.points} threshold="" />;
    } else {
      console.log(this.props.utilizationForInterface);
      return <DetailedChart data={this.props.utilizationForInterface} />;
    }
  }

  displayHeader() {
    return (
      <div>
        <div
          class="row"
          style={{
            fontFamily:
              "HelveticaNeue-Light, Helvetica Neue Light, Helvetica Neue, Helvetica, Arial, Lucida Grande, sans-serif",
            padding: "10px",
            fontSize: "1rem",
            fontWeight: "400"
          }}
        >
          <div className="col-md-6 ">
            <div
              class="row"
              style={{
                fontFamily:
                  "HelveticaNeue-Light, Helvetica Neue Light, Helvetica Neue, Helvetica, Arial, Lucida Grande, sans-serif",
                padding: "10px",
                color: "#595959"
              }}
            >
              {/* <div class="col-md-12">Megaport Name: {this.props.data.Megaport_Name}</div> */}
            </div>
            <div class="row" style={{ padding: "10px", color: "#595959" }}>
              <div class="col-md-12">
                Interface Name: {this.props.data.interface_name}
              </div>
            </div>
          </div>
          <div class="col-md-4">
            <div class="container-fluid">
              <div class="row" style={{ padding: "10px" }}>
                <div style={{ color: "#595959" }}> Choose Date Range </div>
              </div>
              <DateRangePickerWrapper setDates={this.handleChangeDates} />
            </div>
          </div>
          <div class="col-md-2">
            <div class="container-fluid">
              <div class="row" style={{ padding: "10px" }}>
                <Button
                  onClick={this.handleShowTodaysData}
                  variant="outlined"
                  color="secondary"
                >
                  Today's data
                </Button>
              </div>
            </div>
          </div>
        </div>
      </div>
    );
  }

  displayFooter() {
    return (
      <div>
        <div
          class="container-fluid"
          style={{
            fontFamily:
              "HelveticaNeue-Light, Helvetica Neue Light, Helvetica Neue, Helvetica, Arial, Lucida Grande, sans-serif",
            padding: "10px",
            fontSize: "1rem",
            fontWeight: "400"
          }}
        >
          <div class="row">
            <div class="col-md-4">
              Time period : {this.state.isForADate amp;amp; this.props.dte}{" "}
              {!this.state.isForADate amp;amp;
                this.state.fromDate.format("DD-MM-YYYY")}{" "}
              {!this.state.isForADate amp;amp; <label>-</label>}{" "}
              {!this.state.isForADate amp;amp; this.state.toDate.format("DD-MM-YYYY")}
            </div>
            {/* <div class="col-md-4">Region: {this.props.data.region}</div> */}
            {/* <div class="col-md-4">Path: {this.props.data.path} </div> */}
          </div>
          <div class="row">
            {/* <div class="col-md-4">Provisioned Date: {this.props.data.Provisioned_Date}</div> */}
            {/* <div class="col-md-4">Provisioning Status: {this.props.data.Provisioning_Status}</div> */}
          </div>
        </div>
      </div>
    );
  }

  render() {
    return (
      <div color="#595959">
        <Dialog
          ref="dialog"
          open={this.props.dialogStatus}
          onClose={this.props.handleClose}
          aria-labelledby="alert-dialog-title"
          aria-describedby="alert-dialog-description"
          fullWidth={true}
          maxWidth={"md"}
        >
          {this.displayHeader()}

          {this.renderGraph()}

          <DialogContent>
            <DialogContentText id="alert-dialog-description">
              {this.displayFooter()}
            </DialogContentText>
          </DialogContent>
          <DialogActions>
            <Button onClick={this.props.handleClose} color="primary">
              Close
            </Button>
          </DialogActions>
        </Dialog>
      </div>
    );
  }
}

const mapStateToProps = state => {
  console.log(state.singleInterfaceStats);
  return {
    utilizationForInterface: state.singleInterfaceStats.single_interface_data
  };
};

const mapDispatchToProps = dispatch => {
  console.log("Dispatch");
  return {
    onInterfaceStats: (id, from_date, to_date) =>
      dispatch(actionCreators.interfaceStatsByID(id, from_date, to_date))
    // clearUtilizationForVxc : () =>  dispatch(actionCreators.clearUtilizationForVxc())
  };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(InterfaceDetailsDialog);
  

Я не могу понять, почему состояние не обновляется.

Ответ №1:

Сначала вы обновляете состояние, а затем просто передаете fromDte и toDte вместо this.state.fromDte и `this.state .toDte.

 this.setState(
{
    isForADate: false,
    fromDate: fromDte,
    toDate: toDte
});

this.props.onInterfaceStats(
    this.props.data.id,
    fromDte.format("DD-MM-YYYY"),
    toDte.format("DD-MM-YYYY")
);
  

Что я бы порекомендовал вам, так это то, что вы проходите fromDte и toDte как есть, без .format('DD-MM-YY') . Вы выполняете этот формат внутри onInterfaceStats функции.

Ответ №2:

в render функции handleChangeDates должно быть binded to this .

<DateRangePickerWrapper setDates={this.handleChangeDates} />

Для

<DateRangePickerWrapper setDates={this.handleChangeDates.bind(this)} />

если componentDidMount он тоже не обновляется state , вам нужно будет создать constructor и назначить componentDidMount componentDidMount.bind(this) .

Комментарии:

1. Но если вы используете функцию со стрелкой, нет необходимости привязываться к этому

Ответ №3:

попробуйте сделать:

 this.setState(
  {
    isForADate: false,
    fromDate: Object.assign({}, fromDte),
    toDate: Object.assign({}, toDte)
  },
...
)
  

вместо:

   {
    isForADate: false,
    fromDate: fromDte,
    toDate: toDte
  },
  

Комментарии:

1. Я попробовал этот подход, все еще не работает, любая другая идея