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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With