Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

setstate inside render method - Reactjs

Tags:

reactjs

I have a form that contains several questions. Some of the questions are having a set of sub-questions. These are rendered using the following code.

    {
  Object.keys(this.props.moduleDetails.questions).map((questionInfo, index) => (
    <div key={index}>
      <QuestionAnswers
        questionInfo={this.props.moduleDetails.questions[questionInfo]}
        generateStepData={this.props.generateStepData}
        states={this.props.states}
        userEnteredValues={this.props.formValues}
        errors={this.props.errors}
        setQuestionAnswers={this.setQuestionAnswers}
      />
      {this.props.moduleDetails.questions[questionInfo].question_group &&
      this.props.moduleDetails.questions[questionInfo].has_grouped_questions ===
        1 ? (
        <div className="sub-questions">
          {this.props.moduleDetails.questions[questionInfo].question_group ? (
            <span>
              {this.renderQuestionGroup(questionInfo)}
              <input
                type="button"
                onClick={e => {
                  this.addQuestionGroup(questionInfo)
                }}
                value="Add"
                className="btn"
              />
            </span>
          ) : null}
        </div>
      ) : null}
    </div>
  ))
}

As you can see, the question groups are rendered using the renderQuestionGroup(questionInfo) method.

renderQuestionGroup(questionInfo) {
    let input = [];
    this.state.groupedQuestions[questionInfo] = (this.state.groupedQuestions[questionInfo]) ?
                    this.state.groupedQuestions[questionInfo]
                    : [];
    let answerId = this.props.formValues[questionInfo];
    let groupedQuestions = this.props.moduleDetails.questions[questionInfo].question_group[answerId];
    if((groupedQuestions != null && this.state.groupedQuestions[questionInfo].length == 0) || this.state.isAddPressed) {
        this.state.groupedQuestions[questionInfo].push(groupedQuestions);

    }
    input = this.display(questionInfo)
    return input;
  }

The problem here is that I cannot set state inside this method, as this method is called inside render method

Any idea on how to fix this?

Is there any alternate approach for this?

like image 889
prajeesh Avatar asked Dec 02 '22 11:12

prajeesh


2 Answers

You can not set state inside render function because it will cause side effect.

What exactly happens is that each time you update state react calls render function, so if you will update state inside render function then it will stuck inside infinite loop.

In general, this should never happen; you should not be doing anything remotely related to modifying any component's state within a render function.

like image 142
Aumkar Thakur Avatar answered Dec 05 '22 00:12

Aumkar Thakur


You need to move your set state logic to

 componentDidUpdate(prevProps, prevState, snapshot) {
        if (prevPros.prop !=== this.props.prop) {
          /* your setState logic*/
        }
      }

And then just use modified state in renderQuestionGroup.

Also never modify state directly with:

this.state.groupedQuestions[questionInfo] = (this.state.groupedQuestions[questionInfo]) ?
                this.state.groupedQuestions[questionInfo]
                : [];

Use setState({groupedQuestions: [...groupedQuestions,updatedGroup })

from react set state docs:

NEVER mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.

setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.

There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.

setState() will always trigger a re-render unless conditional rendering logic is implemented in shouldComponentUpdate(). If mutable objects are being used and the logic cannot be implemented in shouldComponentUpdate(), calling setState() only when the new state differs from the previous state will avoid unnecessary re-renders.

like image 22
layonez Avatar answered Dec 05 '22 00:12

layonez