skip to Main Content

I am want to handle nested array using react hook from that’s my task. I am able to do everything but the state is not setting on onChange while I am getting all the correct value.
This is how my array looks like

  const { register, handleSubmit, setValue, getValues } = useForm({
defaultValues: {
  quizData: [{
    pId: 1,
    questions: [{ que: 'QUESTION 1', options: ['option 1', 'option 2'], correctAnswer: 0, selectedAnswer: -1 }, { que: 'QUESTION 2', options: ['option 1', 'option 2'], correctAnswer: 0, selectedAnswer: -1 }]
  }]
}
});

Selected answer is not been updated below is link for codesandbox you can run the app over there.

Code Sandbox link

2

Answers


  1. import React, { useEffect } from "react";
    import { useForm } from "react-hook-form";
    
    function Quiz() {
      const { register, handleSubmit, setValue, getValues } = useForm({
        defaultValues: {
          quizData: [
            {
              pId: 1,
              questions: [
                {
                  que: "QUESTION 1",
                  options: ["option 1", "option 2"],
                  correctAnswer: 0,
                  selectedAnswer: -1,
                },
                {
                  que: "QUESTION 2",
                  options: ["option 1", "option 2"],
                  correctAnswer: 0,
                  selectedAnswer: -1,
                },
              ],
            },
          ],
        },
      });
    
      useEffect(() => {
        // Manually set selected values after component mounts
        const data = getValues("quizData");
        data.forEach((p, pIndex) => {
          p.questions.forEach((q, qIndex) => {
            setValue(
              `quizData[${pIndex}].questions[${qIndex}].selectedAnswer`,
              q.selectedAnswer
            );
          });
        });
      }, [getValues, setValue]);
    
      const handleAnswerChange = (pIndex, qIndex, event) => {
        console.log(pIndex, qIndex, event.target.value);
        const newValue = parseInt(event.target.value);
        setValue(
          `quizData[${pIndex}].questions[${qIndex}].selectedAnswer`,
          newValue
        );
      };
    
      const onSubmit = (data) => {
        console.log(data);
      };
    
      return (
        <form onSubmit={handleSubmit(onSubmit)}>
          {getValues("quizData", []).map((p, pIndex) => (
            <div key={p.pId}>
              {p.questions.map((q, qIndex) => (
                <div key={q.que}>
                  <h3>{q.que}</h3>
                  <select
                    {...register(
                      `quizData[${pIndex}].questions[${qIndex}].selectedAnswer`
                    )}
                    onChange={(event) => handleAnswerChange(pIndex, qIndex, event)}
                  >
                    <option value={-1}>Select an option</option>
                    {q.options.map((option, index) => (
                      <option key={index} value={index}>
                        {option}
                      </option>
                    ))}
                  </select>
                </div>
              ))}
            </div>
          ))}
          <button type="submit">Submit</button>
        </form>
      );
    }
    
    export default Quiz;
    

    Try these steps and see if they help resolve the issue. Let me know if you need further assistance!

    Login or Signup to reply.
  2. Update your code as bellow:

    import React from "react";
    import { useForm } from "react-hook-form";
    
    function Quiz() {
      const { register, handleSubmit, setValue, getValues, watch } = useForm({
        defaultValues: {
          quizData: [
            {
              pId: 1,
              questions: [
                {
                  que: "QUESTION 1",
                  options: ["option 1", "option 2"],
                  correctAnswer: 0,
                  selectedAnswer: -1,
                },
                {
                  que: "QUESTION 2",
                  options: ["option 1", "option 2"],
                  correctAnswer: 0,
                  selectedAnswer: -1,
                },
              ],
            },
          ],
        },
      });
    
      const handleAnswerChange = (pIndex, qIndex, event) => {
        console.log(pIndex, qIndex, event.target.value);
        const newValue = parseInt(event.target.value);
        setValue(`quizData.${pIndex}.questions.${qIndex}.selectedAnswer`, newValue);
      };
    
      const onSubmit = (data) => {
        console.log(data);
      };
    
      return (
        <form onSubmit={handleSubmit(onSubmit)}>
          {watch("quizData").map((p, pIndex) => (
            <div key={p.pId}>
              {p.questions.map((q, qIndex) => (
                <div key={q.que}>
                  <h3>{q.que}</h3>
                  <select
                    {...register(
                      `quizData[${pIndex}].questions[${qIndex}].selectedAnswer`
                    )}
                    value={q.selectedAnswer}
                    onChange={(event) => handleAnswerChange(pIndex, qIndex, event)}
                  >
                    <option value={-1}>Select an option</option>
                    {q.options.map((option, index) => (
                      <option key={index} value={index}>
                        {option}
                      </option>
                    ))}
                  </select>
                </div>
              ))}
            </div>
          ))}
          <button type="submit">Submit</button>
        </form>
      );
    }
    
    export default Quiz;
    

    Changes:

    • You can set the value of array element using ‘.’
    // other code
        setValue(`quizData.${pIndex}.questions.${qIndex}.selectedAnswer`, newValue);
    // other code
    
    • You have to use watch() function for rendering updated form values
    // other code
    {watch("quizData").map((p, pIndex) => (
      <div key={p.pId}>
        {p.questions.map((q, qIndex) => (
          <div key={q.que}>
            <h3>{q.que}</h3>
            <select
              {...register(
                `quizData[${pIndex}].questions[${qIndex}].selectedAnswer`
              )}
              value={q.selectedAnswer}
              onChange={(event) => handleAnswerChange(pIndex, qIndex, event)}
            >
              <option value={-1}>Select an option</option>
              {q.options.map((option, index) => (
                <option key={index} value={index}>
                  {option}
                </option>
              ))}
            </select>
          </div>
        ))}
      </div>
    ))}
    // other code
    

    Learn more here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search