S.Adikaram
S.Adikaram

Reputation: 490

Setting a object array to a state variable in React

I am having a problem of updating a state array variable. I have looked fro many resources but none was worked.

I have Updated the code to view the full architecture of how the methods are linked to one another

This is how i defined the array in the state initially.

   constructor(props) {
         super(props);

         this.state = {
          test:[]
         }
       }

This is the render method. inside render method i have called to getQuizView() method

   render(){
        return ( 
          <div> 
            {this.getQuizView()}
          </div> 
        )
      }

and inside getQuizView() method i have called to my updateArray() method

  getQuizView(){
  return (
        <div>
          {this.updateArray()}
        </div>        
  )
}

The following method (updateArray()) is used to update the state variable.

updateArray(){
     for(var i=0; i<this.props.questions.length;i++){
      this.setState({ test: [...this.state.test, {id: this.props.questions[i].questionId, active: '0'}] })
    }
}

But it seems like setState is happening infinitely. but this.props.questions.length = 34

Upvotes: 1

Views: 8380

Answers (2)

Tiisetso Tjabane
Tiisetso Tjabane

Reputation: 2106

The problem is that you are updating the state in the render() method. The render method is not supposed to have side effects, it must be purely for "rendering" your DOM.

The way react works is that whenever you update the state outside the constructor() it calls the render method, just look at the life cycle diagram react life cycle

This is a good source React component

What you are doing is while rendering you update the state(updateArray()) which in turn will cause the render function to be called again then the render function will update the state(updateArray()) and it results in an infinite loop.

[render]-> [update state(updateArray())] -> render -> [update state].....

Just remove the updateArray() method from the render to the other life cycle hooks like componentDidMount()

if you want to show the questions just update getQuizView

   getQuizView(){
      return (
        <div>
          {this.props.questions.map((val)=>{
               <div>val</div>
                 })
           }
        </div>        
      )
  }

Upvotes: 0

Hemadri Dasari
Hemadri Dasari

Reputation: 34014

The reason it goes into inifite loop because you are doing setState in for loop never do that. What you can do is take a local array variable and assign it with this.state.test array and push objects into it. Finally do the setState outside for loop.

You can try below code to avoid infinite loop.

  updateArray(){
       const questions = this.state.test;
       for(var i=0; i<this.props.questions.length;i++){
            questions.push({'id': this.props.questions[i].questionId, 'active': '0'});
      }
     this.setState({
         test: questions
    });
  }

You can even Do the same with map or forEach instead of for loop

Using .forEach:

updateArray(){
   const questions = this.state.test;
   this.props.questions.forEach(item => {
        questions.push({'id': item.questionId, 'active': '0'});
  });
 this.setState({
     test: questions
});
}

Using .map:

 updateArray(){
   const questions = this.props.questions.map(item => {    
             const object = {'id': item.questionId, 'active': '0'};
             return obj;
       });
  const allQuestions = [...this.state.test, questions];
  this.setState({
     test: allQuestions
  });
}

The difference between forEach and map is, forEach doesn’t return new array whereas map returns a new array

Upvotes: 2

Related Questions