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

  1. Если пользователь ничего не вводит в поле имени пользователя, приложение должно показать сообщение «Введите имя пользователя». Если пользователь вводит имя пользователя, отличное от «Юрчик», приложение должно показывать сообщение «Имя пользователя неверно».
  2. Если пользователь ничего не вводит в поле пароля, в приложении должно появиться сообщение «Введите ваш пароль».

Затем перейдите в 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, и что вы дадите ему выстрел в следующий раз, когда вы создадите компонент формы для своего приложения.

Вы можете посмотреть весь код этого компонента формы здесь, он чуть изменен, но суть остается одна.

--

--

Iurii Kalashnikov
FreeCodeCamp Russia(Русскоязычный)

Программист, бразильское джиу джитсу. https://github.com/YKalashnikov давайте дружить