Построение отличных форм в React с использованием Redux-Form
Redux-Form — еще одна потрясающая библиотека Redux, которая дает нам новый способ управления состоянием наших форм в приложении React.
Redux-Form не только интегрирует состояние нашей формы с другим состоянием, которым управляет Redux, но также позволяет отслеживать состояние формы с высокой точностью с помощью Redux Dev Tools.
В этом артикле я покажу вам, как связать Redux-Form с React App, а также переходить к таким вещам, как проверка и создание компонентов многоразовой формы.
Настройка приложения(App Setup)
Давайте создадим новый React App, используя приложение create-react-app. Спасибо Фейсбуку за create-react-app, установка React App становится намного проще, я рекомендую в свободное время создать React App без помощи create-react-app. Я назову свое приложение Form.
$ create-react-app form
$ cd form
Теперь давайте установим пару зависимостей для этого проекта. Мне нужно redux для управления состоянием, react-redux, чтобы связать Redux с React и redux-form чтобы обрабатывать формы, которые я собираюсь создать в этом приложении.
yarn add redux react-redux redux-form
Затем откройте каталог приложения(App directory) в редакторе кода (мне нравится код VS) и удалите все файлы внутри папки src, за исключением файла index.js. Мы собираемся писать собственные файлы.
Создайте новую папку внутри src и назовите ее App. Внутри создайте новый файл index.js со следующим кодом:
Перейдите в src / index.js и удалите ссылку на файлы, которые мы только что удалили. Затем импортируйте компонент Provider Component из функций react-redux и createStore и combineReducers из redux. Мне также нужно импортировать reducer из redux-form. Но, чтобы избежать конфликтов, я сделаю это, переименовав его как formReducer.
import {Provider} from 'react-redux';
import {createStore, combineReducers} from 'redux';
import {reducer as formReducer} from 'redux-form';
Теперь мне нужно указать, что formReducer является одной из app reducer приложения.
const reducers = {form: formReducer};
В реальном мире app у вас будет не один reducer. Вам нужно будет указать их все здесь внутри объекта reducers. После указания reducers нам необходимо объединить их все в один reducer, используя функцию combReducers следующим образом:
const reducer = combineReducers(reducers);
Наконец, мы создадим наш redux store, используя функцию createStore. Я передам reducer в качестве аргумента этой функции.
let store = createStore(reducer);
Даже если у вас есть единственный reducer в вашем приложении, вам все равно придется это делать.
Осталось только еще одно. Оберните App Component c Provider внутри функции render ReactDOM. Provider помогает нам передать store в наш App component.
ReactDOM.render(
<Provider store={store}>
<App>
</Provider>,
document.getElementById('root')
);
Строим форму с помощью Redux-Form
Давайте построим форму.
Создайте новую папку внутри src, называемых components. Эта структура папок чрезвычайно полезна для разбивки моего приложения на блоки кода, которые впоследствии могут быть повторно использованы и в других проектах.
Внутри папки components создайте еще одну папку под названием LoginForm. Эта папка будет содержать файл index.js с этим кодом.
Во-первых, я импортирую React и Component из пакета React. Поскольку я собираюсь создать форму в этом файле, мне нужно несколько вещей из пакета redux-form, называемого Field и reduxForm.
Затем создайте новый класс, называемый LoginForm. Здесь я использую поле для создания полей формы Username и Password. У меня также есть кнопка «Submit» внутри этой формы.
Компонент Field имеет пару props внутри него. Name prop действует как идентификатор поля, а component prop ссылается на элемент html. Здесь мне нужно, чтобы Field действовало как элемент ввода, поэтому я устанавливаю значение component prop в качестве input.
Мне также нужно подключить метод onSubmit к форме. Я передам другой метод, называемый handleSubmit, который будет поступать из наших props.
reduxForm используется для украшения компонента LoginForm. Мне нужно передать имя для этого, вот что я использовал login для входа сюда. Остается только экспортировать его. Осталось только импортировать его в src/App/index.js и вызвать его внутри метода рендеринга компонента App.
Мы также передаем ему метод onSubmit, называемый this.submit. Метод submit здесь будет просто уведомлять меня о значениях, которые пользователь вводит в форму.
Запустите start script в терминале, используя NPM / Yarn(я предпочитаю Yarn), введите некоторые значения в поле, и вы получите это как результат.
Передача многоразовых компонентов (Reusable Components) в Field
Взгляните на компонент Field для Username. Хотя мы передаем строку в компонентную prop, мы можем добиться лучшего контроля над нашей формой, если мы передадим компонент.
Давайте создадим новую папку внутри компонентов под названием Field. Создайте файл с именем index.js и напишите в нем следующий код.
После импорта React я просто создал собственное поле ввода, которое может принимать props.
Вернитесь к файлу LoginForm/index.js и передайте компонент myInput в качестве опоры в обоих компонентах Field.
<Field
name="username"
component={myInput}
type="text"
placeholder="Username"
/>
<Field
name="password"
component={myInput}
type="password"
placeholder="Password"
/>
Если вы посмотрите на приложение в браузере, вы увидите, что ничего не изменилось :)
Начальные значения формы
Если мы хотим установить начальные значения по умолчанию для наших полей формы, то и redux-form также позволяет нам! Чтобы установить начальное значение, нам нужно передать prop, называемый initialValues, в компонент формы.
Перейдите в файл src/App/index.js и передайте команду initialValues в компонент LoginForm. Эта поддержка должна вызвать другую функцию, в которой мы фактически сохраняем начальные значения.
<LoginForm
onSubmit={this.submit}
initialValues={this.getInitialValues()}
/>
Нам также необходимо определить getInitialValues()
. getInitialValues
вернет объект, ключи которого соответствуют именам полей формы.
getInitialValues () {
return {
username: 'Юрчик',
password: '',
};
}
Reload the app page and you will see that the username
field already has a value inside it.
Проверка на стороне клиента (Client-Side Validation)
Есть два способа, которыми мы можем использовать для управления валидацией в redux-form.
Использование функции валидации
Создаем новую папку внутри src под названием Validation. Эта папка будет содержать файл index.js со следующим кодом.
Я создал функцию, называемая validate, которая inputs из формы и изначально имеет пустой объект errors.
Затем я перечислил несколько сценариев ошибок и то, что я хочу, чтобы redux-form выполнялась при возникновении такого сценария.
- Если пользователь ничего не вводит в поле имени пользователя, приложение должно показать сообщение «Введите имя пользователя». Если пользователь вводит имя пользователя, отличное от «Юрчик», приложение должно показывать сообщение «Имя пользователя неверно».
- Если пользователь ничего не вводит в поле пароля, в приложении должно появиться сообщение «Введите ваш пароль».
Затем перейдите в LoginForm/index.js и под полем input, добавьте следующий код:
{
meta.error && meta.touched &&
<div>
{meta.error}
</div>
}
Что делает этот код, так это то, что он сначала проверяет, где есть какие-либо данные, хранящиеся внутри объекта error. Если это так, он проверяет, взаимодействовал ли пользователь с полем ввода. Если это так, то приложение вернет данные, хранящиеся внутри объекта error.
Наконец, нам нужно перейти в файл index.js внутри папки LoginForm, импортировать функцию проверки и вызвать ее внутри декоратора reduxForm.
import {validate} from '../../Validation';
...LoginForm = reduxForm ({
form: 'login',
validate,
}) (LoginForm);
Перезагрузите страницу приложения в браузере, и теперь вы сможете увидеть ошибки при взаимодействии.
Использование проверки на уровне поля (Field-Level Validation)
При проверке на уровне поля мы передаем функции проверки непосредственно в поле. Таким образом, вместо того, чтобы иметь одну гигантскую функцию, вместо этого у нас будет несколько более мелких функций, которые касаются конкретных сценариев, связанных с валидацией.
Удалите все внутри функции Validation/index.js и вместо этого напишите следующий фрагмент кода.
Во-первых, я создал функцию проверки, называемую requireInput, которая проверяет, ввел ли пользователь какой-либо ввод в поле. Если нет, то эта функция вернет сообщение о том, что «Требуется ввод».
Во-вторых, я создал еще одну функцию проверки правильности, называемую rightInput. Эта функция проверяет, является ли вход, заданный пользователем, ожидаемым приложением, а если нет, он вернет сообщение о неправильном вводе.
Теперь нам нужно привязать эти функции к нашей форме. Перейдите в LoginForm / index.js и замените предыдущую инструкцию import для validate функции следующим образом:
import {requiredInput, correctInput} from '../../Validation';
Также удалите ссылку для проверки с помощью декоратора reduxForm. Затем добавьте новый атрибут в поле имени пользователя, которое называется validate и добавьте requiredInput и correctInput.
validate={[requiredInput, correctInput]}
Сделайте то же самое для поля пароля, но только передайте requiredInput.
validate={[requiredInput]}
Доступ к другим значениям поля
Прежде чем идти дальше, давайте создадим новый компонент Field внутри файла LoginForm / index.js.
<Field
name=”confirm-password”
component={myInput}
type=”password”
placeholder=”Confirm Password”
validate={[requiredInput]}
/>
Обычно, когда у нас есть поля «password» и «confirm-password», нам нужно проверить, соответствует ли вход пароля паролю с подтверждением пароля.
To do so, I am going to create a new validation function inside the Validation/index.js
file called matchInput
.
export const matchInput = (input, allInputs) =>input === allInputs.password ? undefined : 'Пароль не совпадает';
Эта функция проверяет ввод поля и проверяет, совпадает ли он с полем ввода пароля.
Остается только импортировать эту новую функцию проверки внутри файла LoginForm / index.js и передать ее в качестве prop в поле Confirm Password.
<Field
name="confirm-password"
component={myInput}
type="password"
placeholder="Confirm Password"
validate={[requiredInput, matchInput]}
/>
Перезагрузите приложение:
Отправить подтверждение (Submit Validation)
В реальном мире форма также должна быть в состоянии проверить, доступно ли имя пользователя, которое мы представляем, или нет. В Redux-Form есть возможность сделать эту проверку, когда пользователь нажимает кнопку отправки.
В файле src / App / index.js импортируйте функцию SubmissionError из редукционной формы.
import {SubmissionError} from 'redux-form';
Затем реструктурируйте метод отправки, как показано ниже:
Здесь метод submit проверяет, существует ли в данном массиве имя пользователя, заданное именем пользователя. Если это так, redux-form выдает ошибку. Иначе это будет работать так, как это было раньше.
В конце…
Разработчик может подумать, что создание форм легко, а в некоторых случаях и так. Но в случае сложных форм, которые содержат много состояний, наличие правильного набора инструментов имеет значение.
Лично я считаю, что Redux-Form может создавать действительно большие формы в React, лучше, чем те, которые React может создавать самостоятельно. Redux-Form также упрощает обработку состояния формы. Способ, которым Redux-Form взаимодействует с React и Redux, действительно потрясающий.
Я надеюсь, что этот пост поможет вам понять, как работает Redux-Form, и что вы дадите ему выстрел в следующий раз, когда вы создадите компонент формы для своего приложения.
Вы можете посмотреть весь код этого компонента формы здесь, он чуть изменен, но суть остается одна.