带有React comonentDidUpdate的无限循环

时间:2018-09-19 02:13:31

标签: reactjs react-router

我有一个父App组件,该组件使用Report组件呈现路线。 App组件在其componentDidMount方法中进行了ajax调用,而Report也在其componentDidUpdate方法中进行了一些ajax调用,这时它调用了父级的updateReports方法。该应用程序陷入无限循环,在此循环中,孩子不断反复进行其ajax调用。

应用

...
  updateReports(report) {
    console.log('updateReports', report)
    if (report.submittal) {
      this.setState({ reports: { submittal: report.submittal } });
      if (report.specification) {
        this.setState({ reports: { specification: report.specification } });
      }
    }
  }
...    
  componentDidMount() {
    console.log('environment', process.env);
    console.log('App state', this.state);
    if (!this.state.projectName) {
      const err = new Error('Project Name must be supplied in the url: /<projectName>');
      return this.handleError(err);
    }

    this.populateProjectId();
  }

  populateProjectId() {
    return Api.getProjectId(process.env.REACT_APP_API_PATH, this.state.projectName)
      .then((projectId) => {
        console.log('App adding projectId to state', projectId);
        this.setState({ projectId });
      })
      .catch((err) => {
        console.log(err);
        this.handleError(err);
      });
  }
...
  render() {
const commonProps = {
  query: this.state.query,
  projectName: this.state.projectName,
  projectId: this.state.projectId
};
...
            <Route
              path="/:projectName/admin"
              render={(props) => (
                <Admin
                  {...{ ...commonProps }} reports={this.state.reports}
                  updateReports={this.updateReports}
                  handleError={this.handleError}
                />
              )}
            />

管理员

...
  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log('Admin componentDidUpdate')
    const { projectId } = this.props;

    const apiPath = process.env.REACT_APP_API_PATH;
    Api.fetchReport(apiPath, projectId, 'submittal', null)
      .then((res) => {
        console.log('submittal report result', res);
        return res;
      })
      .then((submittal) => {
        Api.fetchReport(apiPath, projectId, 'specification', null).then((res) => {
          console.log('specification report result', res);
          const newState = { submittal, specification: res };
          console.log('Calling updateReports', newState);
          this.props.updateReports(newState);
        });
      })
      .catch((err) => {
        console.log(err);
        this.handleError(err);
      });
  }

  render() {
    return (
      <div>
        <Report reports={this.props.reports} />
      </div>
    );
  }
}

export default withRouter(withStyles(styles)(Admin));

1 个答案:

答案 0 :(得分:3)

每当子组件的道具更新时,都会调用

ComponentDidUpdate()。

在这种情况下,流程是:

  1. reports={this.state.reports}传递给子组件
  2. 然后更新孩子,因为reports道具已更改
  3. 调用ComponentDidUpdate(),然后在父组件中触发updateReports(newState)
  4. 在父组件中,状态随新报告一起更新
  5. 更新后的reports={this.state.reports}被传递给孩子
  6. 重复2-5

在这种情况下使用ComponentDidMount()应该可以解决此问题,但更重要的是,从解决方案体系结构的角度来看,应该将服务调用提取到一个单独的文件中并从父级调用,从而使子级成为笨拙的组件。

我可以说很多,但我只是在这里说明为什么会发生循环:P