I am making a user interface to create a quiz. Users can add questions, and within each question they can add/remove choices for the question.
I have a component called CreateQuizPage, which manages state. The questions are stored in "data" (I'm using the useState() hook) as [{questionText: "Here is my question", "choices: ["choice A...","choice B", ...]}, ...]
The question and choices are rendered in my component CreateQuestionPanel
On the CreateQuizPage level I define "addChoiceHandler(idx)" (Where idx is the index of the question for which to add a choice):
const addChoiceHandler = (idx) => {
setData(prev => [...prev.slice(0, idx), { ...prev[idx], choices: prev[idx].choices.concat([""]) }, ...prev.slice(idx + 1)])
}
This function is passed down to the CreateQuestionPanel level, where it is bound to onClick for the "Add choice" button.
<Button basic compact onClick={() => addChoiceHandler(id)}>Add</Button>
Also on the CreateQuestionPanel level, I render choices for the question:
{
choices.map((item, choiceIdx) => {
return (
<Form.Field key={choiceIdx} >
<input
value={item}
name={choiceIdx}
onChange={e => onChoiceTextChange(id, choiceIdx, e.target.value)}
placeholder="Enter choice..."
/>
</Form.Field>
)
})
}
When I click the add choice button in strict mode, the useState hook (setData) fires twice, rendering two choices on click. I read that useState hooks fire twice in strict mode to detect side effects. Does that mean I am using state incorrectly? If I turn strict mode off it works correctly - however I want to make sure I am properly modifying state.
Instead of adding an element to the choices array within the useState hook, should I construct an array with an extra item on the panel level and pass it to useData?