Обновить состояние со значениями переключателя React

avatar
Phaki
8 августа 2021 в 15:51
101
2
0

Интересно, как правильно обновить или установить мое состояние, в котором хранятся значения ответов переключателя. Это тест личности, который состоит из 20 вопросов, и я хотел бы сохранить 20 ответов. У меня есть onChange для каждого ввода переключателя.

Моей целью является хранение данных результатов в некоторой структуре, подобной этой:

[opn1:1,csn1:3,ext1:2,agg1:5,neu1:4,...]

но если бы я мог хранить только значения ответов в правильном порядке, этого тоже было бы достаточно. Проблема в том, что пользователь может изменить свой ответ, и тогда порядок состояния результата будет перепутан.

Мой код: (Это не работает, в результате сохраняется только один ответ)

function Test() {
  const [questions, setQuestions] = useState([]);
  const [answers, setAnswers] = useState([]);
  const [data, setData] = useState(false);
  const [result, setResult] = useState([]);
  const [index, setIndex] = useState(0);
  useEffect(() => {
    StudentService.getTest().then((res) => {
      setQuestions(res.questions);
      setAnswers(res.answers);
      setData(true);
    });
  }, []);

  const onStoreAnswers = (e) => {
    e.preventDefault();
  };
  const storeAnswer = (e) => {
    const qst_id = e.target.id;
    const answ_value = e.target.value;
    setResult((prevState) => ({
      ...prevState,
      qst_id: qst_id,
      answ_value: answ_value,
    }));
  };
  console.log(result);
  if (data) {
    return (
      <form className="container shadow-lg">
        <h1>I am someone who...</h1>
        <h4>{questions[index + 1].qst_title}</h4>
        <div className="form-check form-check-inline">
          <input
            onChange={storeAnswer}
            name={questions[index].qst_id}
            className="form-check-input"
            type="radio"
            id={questions[index].qst_id}
            value={index + 1}
          />
          <label className="form-check-label" htmlFor="inlineCheckbox1">
            {answers[index].answ_id}
          </label>
        </div>
        <div className="form-check form-check-inline">
          <input
            onChange={storeAnswer}
            name={questions[index].qst_id}
            className="form-check-input"
            type="radio"
            id={questions[index + 1].qst_id}
            value={index + 2}
          />
          <label className="form-check-label" htmlFor="inlineCheckbox2">
            {answers[index + 1].answ_id}
          </label>
        </div>
        <div className="form-check form-check-inline">
          <input
            onChange={storeAnswer}
            name={questions[index].qst_id}
            className="form-check-input"
            type="radio"
            id={questions[index + 2].qst_id}
            value={index + 3}
          />
          <label className="form-check-label" htmlFor="inlineCheckbox3">
            {answers[index + 2].answ_id}
          </label>
        </div>
        <div className="form-check form-check-inline">
          <input
            onChange={storeAnswer}
            name={questions[index].qst_id}
            className="form-check-input"
            type="radio"
            id={questions[index + 3].qst_id}
            value={index + 4}
          />
          <label className="form-check-label" htmlFor="inlineCheckbox4">
            {answers[index + 3].answ_id}
          </label>
        </div>

        <div className="form-check form-check-inline">
          <input
            onChange={storeAnswer}
            name={questions[index + 1].qst_id}
            className="form-check-input"
            type="radio"
            id={questions[index + 4].qst_id}
            value={index + 5}
          />
          <label className="form-check-label" htmlFor="inlineCheckbox5">
            {answers[index + 4].answ_id}
          </label>
        </div>
        <h4>{questions[index + 2].qst_title}</h4>
        <div className="form-check form-check-inline">
          <input
            onChange={storeAnswer}
            name={questions[index + 1].qst_id}
            className="form-check-input"
            type="radio"
            id={questions[index].qst_id}
            value={index + 1}
          />
          <label className="form-check-label" htmlFor="inlineCheckbox1">
            {answers[index].answ_id}
          </label>
        </div>
        <div className="form-check form-check-inline">
          <input
            onChange={storeAnswer}
            name={questions[index + 1].qst_id}
            className="form-check-input"
            type="radio"
            id={questions[index + 1].qst_id}
            value={index + 2}
          />
          <label className="form-check-label" htmlFor="inlineCheckbox2">
            {answers[index + 1].answ_id}
          </label>
        </div>
        <div className="form-check form-check-inline">
          <input
            onChange={storeAnswer}
            name={questions[index + 1].qst_id}
            className="form-check-input"
            type="radio"
            id={questions[index + 2].qst_id}
            value={index + 3}
          />
          <label className="form-check-label" htmlFor="inlineCheckbox3">
            {answers[index + 2].answ_id}
          </label>
        </div>
        <div className="form-check form-check-inline">
          <input
            onChange={storeAnswer}
            name={questions[index + 1].qst_id}
            className="form-check-input"
            type="radio"
            id={questions[index + 3].qst_id}
            value={index + 4}
          />
          <label className="form-check-label" htmlFor="inlineCheckbox4">
            {answers[index + 3].answ_id}
          </label>
        </div>
        <div className="form-check form-check-inline">
          <input
            onChange={storeAnswer}
            name={questions[index + 1].qst_id}
            className="form-check-input"
            type="radio"
            id={questions[index + 4].qst_id}
            value={index + 5}
          />
          <label className="form-check-label" htmlFor="inlineCheckbox5">
            {answers[index + 4].answ_id}
          </label>
        </div>
        <h4>{questions[index + 3].qst_title}</h4>
        <h4>{questions[index + 4].qst_title}</h4>
        <button onClick={onStoreAnswers}>Next Page</button>
      </form>
    );
  }
  return (
    <div className="text-center">
      <Spinner className="spinner" animation="border" />
    </div>
  );
}

export default Test;
   "answers":[
      {
         "answ_id":1,
         "answ_title":"Strongly Disagree"
      },
      {
         "answ_id":2,
         "answ_title":"Disagree"
      },
      {
         "answ_id":3,
         "answ_title":"Neither agree nor disagree"
      },
      {
         "answ_id":4,
         "answ_title":"Agree"
      },
      {
         "answ_id":5,
         "answ_title":"Strongly Agree"
      }
   ],
   "questions":[
      {
         "qst_id":"opn1",
         "qst_title":"Is outgoing, sociable"
      },
      {
         "qst_id":"csn1",
         "qst_title":"Very organized and always prepared"
      },
      {
         "qst_id":"ext1",
         "qst_title":"The life of party"
      },
      {
         "qst_id":"agg1",
         "qst_title":"Have a soft heart"
      },
      {
         "qst_id":"neu1",
         "qst_title":"Got stressed out easily"
      },
      {
         "qst_id":"opn2",
         "qst_title":"Full of ideas"
      },
      {
         "qst_id":"csn2",
         "qst_title":"Always pay attention to details"
      },
      {
         "qst_id":"ext2",
         "qst_title":"Feel comfortable around people"
      },
      {
         "qst_id":"agg2",
         "qst_title":"Intrested in people"
      },
      {
         "qst_id":"neu2",
         "qst_title":"Relaxed most of the time"
      },
      {
         "qst_id":"opn3",
         "qst_title":"Do not have a good imagination"
      },
      {
         "qst_id":"csn3",
         "qst_title":"Procrastinate too much"
      },
      {
         "qst_id":"ext3",
         "qst_title":"Do not talk a lot"
      },
      {
         "qst_id":"agg3",
         "qst_title":"Not really interested in other people's problems"
      },
      {
         "qst_id":"neu3",
         "qst_title":"Seldom feel blue"
      },
      {
         "qst_id":"opn4",
         "qst_title":"Have difficulty understanding abstract ideas"
      },
      {
         "qst_id":"csn4",
         "qst_title":"Tend to make a mess of things"
      },
      {
         "qst_id":"ext4",
         "qst_title":"Quite around strangers"
      },
      {
         "qst_id":"agg4",
         "qst_title":"Feel little concern for others"
      },
      {
         "qst_id":"neu4",
         "qst_title":"Have frequent mood swings"
      }
   ]
}

Текущее состояние результата выглядит следующим образом: enter image description here

Если у кого-то есть хорошая идея, как упростить и сделать мой код более читабельным, я открыт для этого. В конце я хотел бы переключаться между страницами, и на каждой странице будет 5 вопросов.

Источник

Ответы (2)

avatar
Phaki
9 августа 2021 в 09:56
1

Ответ Джаярам Каси был почти идеальным. Я внес небольшое изменение в функцию handleAnswerAdd, теперь она добавляет выбранные значения переключателя в состояние результата.

const handleAnswerAdd = (questionKey, answer) => (setResult({
    ...result,
    [questionKey]: answer
 })); 
  if (data) {
    return (
      <form className="container shadow-lg">
        <h1>I am someone who...</h1>

        {questions.map((question) => (
          <div key={question.qst_id}>
            <p>{question.qst_title}</p>

            <div className="form-check form-check-inline">
              <input
                onChange={(e) => {
                  handleAnswerAdd(question.qst_id, e.target.value);
                }}
                name={question.qst_id}
                className="form-check-input"
                type="radio"
                id={question.qst_id}
                value={answers[index].answ_id}
              />
              <label className="form-check-label" htmlFor="inlineCheckbox5">
                1
              </label>
            </div>
            <div className="form-check form-check-inline">
              <input
                onChange={(e) => {
                  handleAnswerAdd(question.qst_id, e.target.value);
                }}
                name={question.qst_id}
                className="form-check-input"
                type="radio"
                id={question.qst_id}
                value={answers[index + 1].answ_id}
              />
              <label className="form-check-label " htmlFor="inlineCheckbox5">
                2
              </label>
            </div>
            <div className="form-check form-check-inline">
              <input
                onChange={(e) => {
                  handleAnswerAdd(question.qst_id, e.target.value);
                }}
                name={question.qst_id}
                className="form-check-input"
                type="radio"
                id={question.qst_id}
                value={answers[index + 2].answ_id}
              />
              <label className="form-check-label " htmlFor="inlineCheckbox5">
                3
              </label>
            </div>
            <div className="form-check form-check-inline">
              <input
                onChange={(e) => {
                  handleAnswerAdd(question.qst_id, e.target.value);
                }}
                name={question.qst_id}
                className="form-check-input"
                type="radio"
                id={question.qst_id}
                value={answers[index + 3].answ_id}
              />
              <label className="form-check-label " htmlFor="inlineCheckbox5">
                4
              </label>
            </div>
            <div className="form-check form-check-inline">
              <input
                onChange={(e) => {
                  handleAnswerAdd(question.qst_id, e.target.value);
                }}
                name={question.qst_id}
                className="form-check-input"
                type="radio"
                id={question.qst_id}
                value={answers[index + 4].answ_id}
              />
              <label className="form-check-label " htmlFor="inlineCheckbox5">
                5
              </label>
            </div>
          </div>
        ))}
        <button onClick={onStoreAnswers}>Next Page</button>
      </form>
    );
  }

Результат: enter image description here

avatar
Jayaram Kasi
8 августа 2021 в 16:47
2

Один из способов взглянуть на это так: вы можете рассматривать каждый ответ как пару ключ-значение. Ключ — это идентификатор или ключ вопроса, а значение — ответ.

const [answers, setAnswers] = useState({});

const handleAnswerAdd = (questionKey, answer) => ({
   ...answers,
   [questionKey]: answer
}); 

const questions = [
      {
         "qst_id":"opn1",
         "qst_title":"Is outgoing, sociable"
      },
      {
         "qst_id":"csn1",
         "qst_title":"Very organized and always prepared"
      },
      {
         "qst_id":"ext1",
         "qst_title":"The life of party"
      },
      {
         "qst_id":"agg1",
         "qst_title":"Have a soft heart"
      },
      {
         "qst_id":"neu1",
         "qst_title":"Got stressed out easily"
      },
      {
         "qst_id":"opn2",
         "qst_title":"Full of ideas"
      },
      {
         "qst_id":"csn2",
         "qst_title":"Always pay attention to details"
      },
      {
         "qst_id":"ext2",
         "qst_title":"Feel comfortable around people"
      },
      {
         "qst_id":"agg2",
         "qst_title":"Intrested in people"
      },
      {
         "qst_id":"neu2",
         "qst_title":"Relaxed most of the time"
      },
      {
         "qst_id":"opn3",
         "qst_title":"Do not have a good imagination"
      },
      {
         "qst_id":"csn3",
         "qst_title":"Procrastinate too much"
      },
      {
         "qst_id":"ext3",
         "qst_title":"Do not talk a lot"
      },
      {
         "qst_id":"agg3",
         "qst_title":"Not really interested in other people's problems"
      },
      {
         "qst_id":"neu3",
         "qst_title":"Seldom feel blue"
      },
      {
         "qst_id":"opn4",
         "qst_title":"Have difficulty understanding abstract ideas"
      },
      {
         "qst_id":"csn4",
         "qst_title":"Tend to make a mess of things"
      },
      {
         "qst_id":"ext4",
         "qst_title":"Quite around strangers"
      },
      {
         "qst_id":"agg4",
         "qst_title":"Feel little concern for others"
      },
      {
         "qst_id":"neu4",
         "qst_title":"Have frequent mood swings"
      }
   ]

И в реагирующем компоненте

questions.map(question=> 
<>
   <div className="form-check form-check-inline">
          <input
            onChange={e=>{
                handleAnswerAdd(question.qst_id, e.target.value);
            }}
            name={question.qst_id}
            className="form-check-input"
            type="radio"
            id={question.qst_id}
            value={answers[question.qst_id]}
          />
          <label className="form-check-label" htmlFor="inlineCheckbox5">
            {
              // Change this to what you want here. not quite sure
              answers[question.qst_id] 
            } 
          </label>
        </div>
        <h4>{question.qst_title}</h4>
</>
);
Phaki
9 августа 2021 в 09:29
1

Привет Джаярам Каси, спасибо за ваш ответ, но он не работает нормально. Это не добавляет выбранное значение радио к состоянию результата.