Reactjs 带有React-ComontDidUpdate的无限循环

Reactjs 带有React-ComontDidUpdate的无限循环,reactjs,react-router,Reactjs,React Router,我有一个父应用程序组件,它使用报表组件呈现路由。应用程序组件在其componentDidMount方法中进行ajax调用,报表也在其componentDidUpdate方法中进行一些ajax调用,此时它调用父级的updateReports方法。这个应用程序陷入了一个无限循环中,在这个循环中,孩子们一次又一次地进行ajax调用 应用程序 。。。 更新报告(报告){ console.log('updateReports',报告) if(报告提交){ this.setState({reports:{s

我有一个父应用程序组件,它使用报表组件呈现路由。应用程序组件在其componentDidMount方法中进行ajax调用,报表也在其componentDidUpdate方法中进行一些ajax调用,此时它调用父级的updateReports方法。这个应用程序陷入了一个无限循环中,在这个循环中,孩子们一次又一次地进行ajax调用

应用程序

。。。
更新报告(报告){
console.log('updateReports',报告)
if(报告提交){
this.setState({reports:{submission:report.submission}});
if(报告规范){
this.setState({reports:{specification:report.specification}});
}
}
}
...    
componentDidMount(){
console.log('environment',process.env);
console.log('App state',this.state);
如果(!this.state.projectName){
const err=new Error('url:/'中必须提供项目名称);
返回此。handleError(err);
}
this.populateprojection();
}
PopulateProjection(){
返回Api.getProjectId(process.env.REACT\u APP\u Api\u路径,this.state.projectName)
.然后((projectd)=>{
log('App adding projectId to state',projectId');
this.setState({projectd});
})
.catch((错误)=>{
控制台日志(err);
这个.handleError(err);
});
}
...
render(){
const commonProps={
查询:this.state.query,
projectName:this.state.projectName,
projectd:this.state.projectd
};
...
(
)}
/>
管理员

。。。
componentDidUpdate(prevProps、prevState、快照){
console.log('Admin componentdiddupdate')
const{projectId}=this.props;
const apiPath=process.env.REACT\u APP\u API\u PATH;
Api.fetchReport(apiPath,projectId,'submission',null)
。然后((res)=>{
控制台日志(“提交报告结果”,res);
返回res;
})
。然后((提交资料)=>{
fetchReport(apiPath,projectId,'specification',null)。然后((res)=>{
console.log('规范报告结果',res);
const newState={提交文件,规格:res};
log('callingupdatereports',newState);
this.props.updateReports(newState);
});
})
.catch((错误)=>{
控制台日志(err);
这个.handleError(err);
});
}
render(){
返回(
);
}
}
使用路由器导出默认值(使用样式(样式)(管理));
每当更新子组件的道具时,都将调用ComponentDidUpdate()

在这种情况下,发生的流程是:

  • reports={this.state.reports}
    被传递给子组件
  • 然后更新子项,因为它的
    报告
    属性已更改
  • 调用ComponentDidUpdate(),然后在父组件中触发更新报告(newState)
  • 在父组件中,使用新报告更新状态
  • 更新的
    reports={this.state.reports}
    将传递给子级
  • 重复2-5次
  • 在此场景中使用ComponentDidMount()可以解决此问题,但更重要的是,从解决方案体系结构的角度来看,您的服务调用应该提取到一个单独的文件中,并从父级调用,使子级成为哑组件

    我可以说很多,但我只是想澄清为什么会发生循环:每当子组件的道具被更新时,就会调用p

    componentdiddupdate()

    在这种情况下,发生的流程是:

  • reports={this.state.reports}
    被传递给子组件
  • 然后更新子项,因为它的
    报告
    属性已更改
  • 调用ComponentDidUpdate(),然后在父组件中触发更新报告(newState)
  • 在父组件中,使用新报告更新状态
  • 更新的
    reports={this.state.reports}
    将传递给子级
  • 重复2-5次
  • 在此场景中使用ComponentDidMount()可以解决此问题,但更重要的是,从解决方案体系结构的角度来看,您的服务调用应该提取到一个单独的文件中,并从父级调用,使子级成为哑组件


    我可以说很多,但我只是想澄清为什么会发生循环:p

    如果我只想在加载子路由时打电话怎么办?最好的处理方法是什么?一切都取决于你需要更新这些报告的频率。。。在父对象的
    ComponentDidMount()
    上,最好只调用一次,然后将其传递给您的子对象,并去掉所有功能,或者在大多数情况下,子对象中的该方法将只调用一次。您也可以在
    构造函数()
    上进行服务调用,但这通常不是最佳做法。如果我只想在加载子路由时进行调用,该怎么办?最好的处理方法是什么?一切都取决于你需要更新这些报告的频率。。。在父对象的
    ComponentDidMount()
    上,最好只调用一次,然后将其传递给您的子对象,并去掉所有功能,或者在大多数情况下,子对象中的该方法将只调用一次。您也可以在
    构造函数()
    上进行服务调用,但这通常不是最佳做法。
    ...
      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));