1

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

4
  • You should only be updating the state once (without a loop). Can you edit into your question the contents of this.props.questions? Commented Sep 22, 2018 at 6:40
  • 1
    where are you calling the updateArray() function? Commented Sep 22, 2018 at 6:40
  • Can you paste full code here or setup fiddler/codesandbox Commented Sep 22, 2018 at 6:43
  • @TiisetsoTjabane i am calling to the updateArray() function inside another function but that function has been called inside render method. Commented Sep 24, 2018 at 3:23

2 Answers 2

2

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

Sign up to request clarification or add additional context in comments.

7 Comments

Don't forget the existing values in this.state.test should be included in setState as well.
Fixed your map example to properly use map instead of copy-pasting forEach :)
The map should happen on this.props.questions but not on this.state.test. Am I right?
@Sulthan the previous test array values also needed and we need to do map on this.props.questions but you did map on this.state.test. Please feel to edit my answer if you have solution for map on questions and also the newly returned array of map should keep existing array values as well. Correct me if I am wrong
Well, you are correct but in that case, map should not be used at all. If you are not using the return value of map, don't use map. You are still using it like a forEach. Probably could be something like: const newQuestions = this.state.test.map(question => ({ ... })); const questions = [...this.state.test, ...newQuestions];
|
0

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>        
      )
  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.