admin管理员组

文章数量:1419573

Can someone help me solve how do I setState inside ponentDidUpdate and not have an infinite loop? Some suggestions said to have a conditional statement, but I am not too familiar with how do I set the conditional for my code.

This is what my code looks like:

I have a dashboard ponent that gets all the panies and projects data from external functions where the fetch happens and then updates the state. The projects are associated with the pany's id.

I am able to get the list of all the projects in JSON, but I can't figure out how to update my projects state inside ponentDidUpdate once rendered.

CompanyDashboard.js

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

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

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

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

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

export default CompanyDashboard;

panyActions.js

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

export function getCompanys() {
    let url = config.base_url + '/panys';
    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(pany) {
  let url = config.base_url + `/panys/${pany._id['$oid']}/projects`;
  return fetch(url, {
    method: 'GET',
    headers: {'token': getUserToken() }
  })
  .then(res => res.json())
  .then(data => { return data })
  .catch(err => console.log(err));
}

Can someone help me solve how do I setState inside ponentDidUpdate and not have an infinite loop? Some suggestions said to have a conditional statement, but I am not too familiar with how do I set the conditional for my code.

This is what my code looks like:

I have a dashboard ponent that gets all the panies and projects data from external functions where the fetch happens and then updates the state. The projects are associated with the pany's id.

I am able to get the list of all the projects in JSON, but I can't figure out how to update my projects state inside ponentDidUpdate once rendered.

CompanyDashboard.js

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

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

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

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

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

export default CompanyDashboard;

panyActions.js

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

export function getCompanys() {
    let url = config.base_url + '/panys';
    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(pany) {
  let url = config.base_url + `/panys/${pany._id['$oid']}/projects`;
  return fetch(url, {
    method: 'GET',
    headers: {'token': getUserToken() }
  })
  .then(res => res.json())
  .then(data => { return data })
  .catch(err => console.log(err));
}
Share Improve this question edited Dec 30, 2019 at 12:03 Afia 6835 silver badges17 bronze badges asked Jul 18, 2018 at 19:08 SamWhiteSamWhite 893 silver badges12 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 1

The following code is not doing anything meaningful. You are setting your state.projects to be equal to your state.projects.

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

Also, the following code is not doing anything meaningful because you are not saving the result of panies.map anywhere.

    {
      panies.map((pany) => {
        return getProjects(pany) 
      })
    } 

It's hard to tell what you think your code is doing, but my guess is that you think that simply calling "panies.map(....) " inside your render function is going to TRIGGER the ponentDidUpdate function. That is not how render works, you should go back to the drawing board on that one. It also looks like you think that using the curly brackets {} inside your render function will display the objects inside your curly brackets. That's also not true, you need to use those curly brackets inside the ponents. For instance: {projects}

If I had to guess... the following code is how you actually want to write your ponent

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

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

  ponentWillMount() {
    getCompanys().then(panies => {
      const projectPromises = panies.map((pany) => {
        return getProjects(pany) 
      });

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

        this.setState({ panies, 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 = panies.map((pany) => {
       *   return getProjects(pany).then(project => this.setState({projects: this.state.projects.concat(project)}));
       * });
       */

    )
  }

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

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

}

export default CompanyDashboard;

ponentDidUpdate has this signature, ponentDidUpdate(prevProps, prevState, snapshot)

This means that every time the method gets called you have access to your prevState which you can use to pare to the new data, and then based on that decide if you should update again. As an example it can look something like this.

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

Of course this is only an example since I don't know your requirements, but this should give you an idea.

When ponentDidUpdate() is called, two arguments are passed: prevProps and prevState. This is the inverse of ponentWillUpdate(). The passed values are what the values were, and this.props and this.state are the current values.

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

You must check the state/props if new state/props different from previous one then you can allow to update your ponent.

You may call setState() immediately in ponentDidUpdate() but note that it must be wrapped in a condition like in the example above, or you’ll cause an infinite loop. It would also cause an extra re-rendering which, while not visible to the user, can affect the ponent performance. If you’re trying to “mirror” some state to a prop ing from above, consider using the prop directly instead.

This is because ponentDidUpdate is called just after a ponent takes up somechanges in the state. so when you change state in that method only then it will move to and from from that method and state change process

本文标签: javascriptReact setState inside componentDidUpdate causing infinite loopStack Overflow