Настраивать
Formik - прекрасная библиотека для ускорения процесса создания форм в React. Он обрабатывает все основные функции, такие как состояние формы, проверка и отправка.
Начнем с создания пустого create-response-app https://create-react-app.dev/
npx create-react-app my-app
Установите библиотеку formik
yarn add formik
Использование компонентов Formik
Удалите созданный пример кода и импортируйте библиотеку formik и некоторые компоненты в App.js. Мы будем использовать реакцию
useState
hook только для того, чтобы показать значения формы в этом примере.
import React, { useState } from 'react' import { Formik, Form, Field } from 'formik'
function App() { const [result, setResult] = useState('')
return ( // Formik is the main component that handles all the logic // Form is just a regular html <form> wrapper <Formik> {() => ( <Form> </Form> )} </Formik> ); }
export default App
Давайте использовать
Field
Компонент formik для создания некоторых полей. Проверьте документацию, чтобы увидеть все возможные доступные реквизиты https://jaredpalmer.com/formik/docs/api/field#props-1
Поле по умолчанию - это input type = ”text”
<Field name="fieldName" />
Для выбора мы указываем параметры как дочерние
<Field as="select" name="color" value="none">
<option value="none">Pick a color</option>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</Field>
В этом примере мы собираемся использовать текстовое поле для отображения значений после отправки.
<Field as="textarea" value={result} rows={5} />
Свойства формы передаются детям, предоставляя множество вариантов для настраиваемых полей.
<Field name="email">
{({ field }) => (
<div>
<label>email:</label>
<input type="email" required placeholder="Email" {...field} />
</div>
)}
</Field>
Мы можем пойти дальше и просто установить компонентную опору. Реквизиты формы будут переданы этому компоненту
function CustomInput({ field, form, ...props }) { return <input {...field} {...props} /> }
<Field name="name" required placeholder="Name" component={CustomInput} />
A
type="submit"
автоматически обрабатывает форму onSubmit
<button type="submit">Submit</button>
Собери все вместе
Это последний пример формы, созданной с помощью formik. Formik нуждается в
initialValues
опора для правильной работы.
import React, { useState } from 'react' import { Formik, Form, Field } from 'formik'
function CustomInput({ field, form, ...props }) { return <input {...field} {...props} /> }
function App() { const [result, setResult] = useState('')
return ( <Formik initialValues={{ email: '', name: '', color: 'red' }} onSubmit={(values, actions) => { setResult(JSON.stringify(values)) }} > {() => ( <Form> <Field as="select" name="color" value="none"> <option value="none">Pick a color</option> <option value="red">Red</option> <option value="green">Green</option> <option value="blue">Blue</option> </Field> <br /> <Field name="email"> {({ field }) => ( <div> <label>email:</label> <input type="email" required placeholder="Email" {...field} /> </div> )} </Field> <br /> <Field name="name" required placeholder="Name" component={CustomInput} /> <br /> <button type="submit">Submit</button> <br /> <br /> <Field style={{ width: '100%'}} as="textarea" value={result} rows={2} /> </Form> )} </Formik> ) }
export default App
Не так уж и красиво, но я не хотел загрязнять код стилями.
Модульное тестирование с помощью библиотеки тестирования React
Обычно для тестирования компонентов достаточно использовать Jest и Enzyme, но с Formik, внутренним состоянием React и события становятся более сложными, а
input.simulate('change')
не работает. К счастью, есть хорошая программа под названием Testing Library, которая поддерживает множество интерфейсных библиотек и фреймворков https://testing-library.com/docs/intro
Прежде всего, установите библиотеку как зависимость разработчика
yarn add --dev '@testing-library/react'
Сначала проверьте, не дает ли приложение сбой
it('renders without crashing', () => {
const div = document.createElement('div')
ReactDOM.render(<App />, div)
})
Теперь давайте выберем все элементы поля, чтобы иметь возможность запускать с ними события.
it('submits correct values', () => {
const { container } = render(<App />)
const name = container.querySelector('input[name="name"]')
const email = container.querySelector('input[name="email"]')
const color = container.querySelector('input[name="color"]')
const submit = container.querySelector('button[type="submit"]')
})
Давай изменим их ценности
fireEvent.change(name, { target: { value: 'mockname' } })
fireEvent.change(email, { target: { value: 'mockemail' } })
fireEvent.change(color, { target: { value: 'mockcolor' } })
Получаем эту ошибку
Warning: An update to Formik inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */
Это означает, что что-то изменилось в Formik state внутри теста, нам нужно дождаться этих изменений. act тоже хорошо, но вместо act мы также можем использовать библиотеку тестирования
wait
Https://testing-library.com/docs/dom-testing-library/api-async#wait
Обратите внимание, что мы изменим тест на
async
it("submits correct values", async () => { const { container } = render(<App />) const name = container.querySelector('input[name="name"]') const email = container.querySelector('input[name="email"]') const color = container.querySelector('select[name="color"]') const submit = container.querySelector('button[type="submit"]') const results = container.querySelector("textarea");
await wait(() => { fireEvent.change(name, { target: { value: "mockname" } }) })
await wait(() => { fireEvent.change(email, { target: { value: "[email protected]" } }) })
await wait(() => { fireEvent.change(color, { target: { value: "green" } }) })
await wait(() => { fireEvent.click(submit) })
expect(results.innerHTML).toBe( '{"email":"[email protected]","name":"mockname","color":"green"}' ) })
Теперь мы получаем правильные результаты, и благодаря библиотеке тестирования мы фокусируемся на функциональности и поведении DOM, а не на деталях React.
Вы можете пойти дальше и прочитать документацию Formik для создания сложных форм и полей. Спасибо за прочтение.
ОБНОВЛЕНИЕ: библиотека тестирования "wait" устарела. Вместо этого используйте "waitFor".