#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. Проблема заключается в части пользовательского интерфейса.