prajeesh
prajeesh

Reputation: 2382

setstate inside render method - 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?

Upvotes: 5

Views: 14468

Answers (2)

layonez
layonez

Reputation: 1785

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.

Upvotes: 7

Aumkar Thakur
Aumkar Thakur

Reputation: 188

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.

Upvotes: 11

Related Questions