Переключатель поля Formik нажат, и значение обновлено, но переключатель не отображается как выбранный

#reactjs #formik

#reactjs #formik

Вопрос:

Я работал над приложением quiz с несколькими переключателями, используя React вместе с Formik. Я не хочу, чтобы переключатели имели defaultChecked атрибут. Отправка формы работает так, как я хотел, значения каждой переключающей кнопки отображаются в режиме оповещения. Но переключатель не отображается как выбранный в браузере.

 import React, { useState } from 'react';
import { Formik, Form, Field } from 'formik';
import {
  Button,
  ButtonGroup,
  Col,
  Container,
  FormGroup,
  Input,
  Label,
  Row,
} from 'reactstrap';
import { Questions, initialValues } from './dummy';
import ModalConfirm from './ModalConfirm';
import './FormQuiz.css';
import ButtonGrid from './ButtonGrid';

function FormQuiz() {
  const [isOpen, setIsOpen] = useState(false);
  const [confirm, setConfirm] = useState(false);

  const [step, setStep] = useState(1);
  const [questions, setQuestions] = useState(Questions);

  const toggle = (e) => setIsOpen(!isOpen);

  const handleSubmit = (e) => {
    e.preventDefault();
    if (!confirm) {
      toggle();
    }
  };

  return (
    <Container className='mt-5'>
      <Row className='mx-2'>
        <Col md={{ size: '6' }} className='m-auto'>
          
          <Formik
            initialValues={initialValues}
            onSubmit={async (values) => {
              await new Promise((r) => setTimeout(r, 500));
              alert(JSON.stringify(values, null, 2));
            }}
          >
            {({ values }) => (
              <Form>
                <div role='group' aria-labelledby='my-radio-group'>
                  {questions.map((question, questionIndex) => (
                    <div
                      key={questionIndex}
                      hidden={questionIndex   1 === step ? false : true}
                    >
                      <h5 className='pl-0 my-5'>
                        {questionIndex   1}
                        {'. '}
                        {question.questionText}
                      </h5>
                      {question.options.map((option, optionIndex) => (
                        <FormGroup
                          key={optionIndex}
                          role='group'
                          className='row'
                        >
                          <Field
                            className='form-control-sm'
                            type='radio'
                            id={`q${questionIndex   1}o${optionIndex   1}`}
                            name={`option${questionIndex   1}`}
                            value={optionIndex   1}
                          />
                          <Label
                            htmlFor={`q${questionIndex   1}o${optionIndex   1}`}
                          >
                            {option}
                          </Label>
                        </FormGroup>
                      ))}
                      <div>{values[`option${questionIndex   1}`]}</div>
                    </div>
                  ))}
                </div>
                <Button
                  color='info'
                  disabled={step === 1 ? true : false}
                  onClick={(e) => setStep(step - 1)}
                  className='mr-1'
                >
                  Previous
                </Button>
                <Button
                  color='primary'
                  disabled={step === questions.length ? true : false}
                  onClick={(e) => setStep(step   1)}
                  className='mr-1'
                >
                  Next
                </Button>

                <Button color='warning' type='submit'>
                  Submit
                </Button>
              </Form>
            )}
          </Formik>
        </Col>
      </Row>
    </Container>
  );
}

export default FormQuiz;  

Вот жестко запрограммированные вопросы и начальные значения dummy.js

 export const Questions = [
  {
    questionText: 'HTML?',
    options: [
      'Hyper Tech Machine Learning',
      'How To Mitigate Linda',
      'How To Master Linguistics',
      'Hyper Text Markup Language',
    ],
    correctOption: 4,
  },
  {
    questionText: 'NodeJS invented by',
    options: ['Carls Linus', 'Ryan Dahl', 'Siraj Raval', 'Bill Gates'],
    correctOption: 2,
  }
];

let values = {};
Questions.forEach((question, index) => {
  values[`option${index   1}`] = '';
});
export let initialValues = values;  

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

Ответ №1:

Будучи пойманным этим сам, я могу вам сказать, что проблема, вероятно, связана с value тем, что атрибут для вашего <Field /> тега JSX является числовым типом, а не строкой (да, я знаю, что это может быть сделано специально, но потерпите меня …).

Если вы измените значение атрибута value на строковое представление числа, пользовательский интерфейс должен обновиться и отобразить переключатель как выбранный.

Код операции:

 <Field
  className='form-control-sm'
  type='radio'
  id={`q${questionIndex   1}o${optionIndex   1}`}
  name={`option${questionIndex   1}`}
  // TODO: value attribute should be the string representation of the numerical value
  value={optionIndex   1} 
/>
  

Я использовал Yup для проверки схемы (как рекомендовано документацией Formik по проверке), и это все равно прошло проверку на обнуляемое требуемое число:

Yup.number().required('Required').nullable()

Если вы заинтересованы в использовании Yup для проверки схемы, похоже, что Yup просто принимает значение и пытается проанализировать его как число. Если значение не может быть проанализировано как число, Yup выдаст NaN сообщение об ошибке, и значение не пройдет проверку.

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

Ответ №2:

Используйте так: 1-я ошибка: используйте то же имя для радиовхода 2-я ошибка: передайте флажок, когда он будет отображаться выбранным

 <Field
          name="gender"
          render={({ field }) => (
            <>
              <div className="radio-item">
                <input
                  {...field}
                  id="male"
                  value="male"
                  checked={field.value === 'male'}
                  name="type"
                  type="radio"
                />
                <label htmlFor="male">Male</label>
              </div>

              <div className="radio-item">
                <input
                  {...field}
                  id="female"
                  value="female"
                  name="type"
                  checked={field.value === 'female'}
                  type="radio"
                />
                <label htmlFor="female">Female</label>
              </div>
            </>
          )}
        />
  

Комментарии:

1. В моем случае это не совсем помогает. В моем случае у меня есть два вложенных цикла. У каждого вопроса должны быть переключатели с тем же именем. Но каждый вариант каждого вопроса не может иметь одно и то же имя prop. Проблема заключается в части пользовательского интерфейса.