在componentDidUpdate内部反应setState导致无限循环

时间:2018-07-18 19:08:44

标签: javascript json reactjs infinite-loop

有人可以帮助我解决如何在componentDidUpdate内设置setState且没有无限循环吗?一些建议说有条件,但是我对如何为我的代码设置条件不是很多。

这是我的代码的样子:

我有一个仪表板组件,该组件可从发生提取的外部功能中获取所有公司和项目数据,然后更新状态。这些项目与公司的ID相关联。

我能够获取JSON中所有项目的列表,但是我不知道如何在呈现后在componentDidUpdate中更新我的项目状态。

CompanyDashboard.js

import { getCompanys } from "../../actions/companyActions";
import { getProjects } from "../../actions/projectActions";

class CompanyDashboard extends Component {
  constructor(props) {
    super(props);
    this.state = {
      companies: [],
      projects: []
    };
  }

  componentWillMount() {
    // get all companies and update state
    getCompanys().then(companies => this.setState({ companies }));
  }

  componentDidUpdate(prevState) {
    this.setState({ projects: this.state.projects });
  }

  render() {
    const { companies, projects } = this.state;
    {
      companies.map(company => {
        // get all the projects
        return getProjects(company);
      });
    }
    return <div />;
  }
}

export default CompanyDashboard;

companyActions.js

import { getUser, getUserToken } from './cognitoActions';
import config from '../../config';

export function getCompanys() {
    let url = config.base_url + '/companys';
    return fetch(url, {
      method: 'GET',
      headers: {'token': getUserToken() }
    })
    .then(res => res.json())
    .then(data => { return data })
    .catch(err => console.log(err));
}

projectActions.js

import { getUserToken } from './cognitoActions';
import config from '../../config';

export function getProjects(company) {
  let url = config.base_url + `/companys/${company._id['$oid']}/projects`;
  return fetch(url, {
    method: 'GET',
    headers: {'token': getUserToken() }
  })
  .then(res => res.json())
  .then(data => { return data })
  .catch(err => console.log(err));
}

4 个答案:

答案 0 :(得分:0)

componentDidUpdate具有此签名,componentDidUpdate(prevProps, prevState, snapshot)

这意味着,每次调用该方法时,您都可以访问prevState,可以将其与新数据进行比较,然后根据该决定来决定是否应再次更新。例如,它看起来可能像这样。

componentDidUpdate(prevProps, prevState) {
  if (!prevState.length){
    this.setState({ projects: this.state.projects })
  }
}

当然,这只是一个例子,因为我不知道您的要求,但这应该可以使您有所了解。

答案 1 :(得分:0)

这是因为componentDidUpdate在组件占用状态的某些更改后立即被调用。因此,当您仅在该方法中更改状态时,它将在该方法和状态更改过程之间来回移动

答案 2 :(得分:0)

以下代码没有做任何有意义的事情。您正在将state.projects设置为与state.projects相等。

  componentDidUpdate() {
    this.setState({ projects: this.state.projects })
  }

此外,下面的代码没有做任何有意义的事情,因为您没有将companies.map的结果保存在任何地方。

    {
      companies.map((company) => {
        return getProjects(company) 
      })
    } 

很难说出您的代码在做什么,但是我的猜测是,您认为仅在render函数中调用“ companies.map(....)”将触发componentDidUpdate函数。那不是渲染的工作原理,您应该回到那个渲染板上。您似乎还认为,在render函数中使用大括号{}将显示大括号内的对象。这也不是正确的,您需要在组件内部使用大括号。例如:{projects}

如果我不得不猜测...下面的代码是您实际想要编写组件的方式

import { getCompanys } from '../../actions/companyActions';
import { getProjects } from '../../actions/projectActions';

class CompanyDashboard extends Component {
  constructor(props) {
    super(props);
    this.state = {
      companies: [],
      projects: []
    }
  }

  componentWillMount() {
    getCompanys().then(companies => {
      const projectPromises = companies.map((company) => {
        return getProjects(company) 
      });

      Promise.all(projectPromises).then(projects => {
        //possibly a flatten operator on projects would go here.

        this.setState({ companies, projects });
      });


      /*
       * Alternatively, you could update the state after each project call is returned, and you wouldn't need Promise.all, sometimes redux can be weird about array mutation in the state, so look into forceUpdate if it isn't rerendering with this approach:
       * const projectPromises = companies.map((company) => {
       *   return getProjects(company).then(project => this.setState({projects: this.state.projects.concat(project)}));
       * });
       */

    )
  }

  render() {
    const { companies, projects } = this.state;

    //Not sure how you want to display companies and projects, but you would 
    // build the display components, below.
    return(
      <div>
         {projects}
      </div>
    )
  }

}

export default CompanyDashboard;

答案 3 :(得分:0)

  

调用componentDidUpdate()时,将传递两个参数:   prevPropsprevState。这是逆的   componentWillUpdate()。传递的值就是这些值,   this.propsthis.state是当前值。

`componentDidUpdate(prevProps) {
    if (this.props.userID !== prevProps.userID) {
        this.fetchData(this.props.userID);
    }
}`

如果新状态/道具不同于先前的状态/道具,则必须检查状态/道具,然后才能允许更新组件。

  

您可以立即在setState()中致电componentDidUpdate(),但   请注意,必须将其包装在如上例所示的条件下,   否则会导致无限循环。这也会造成额外的   重新渲染虽然对用户不可见,但可能会影响   组件性能。如果您尝试将某些状态“镜像”到   道具来自上方,请考虑直接使用道具。