react отправка формы на сервер

Работа с формами в React.js, используя базовый инструментарий

Введение

За время работы на React.js мне часто приходилось сталкиваться с обработкой форм. Через мои руки прошли Redux-Form, React-Redux-Form, но ни одна из библиотек не удовлетворила меня в полной мере. Мне не нравилось, что состояние формы хранится в reducer, а каждое событие проходит через action creator. Также, согласно мнению Дана Абрамова, «состояние формы по своей сути является эфемерным и локальным, поэтому отслеживать его в Redux (или любой библиотеке Flux) не нужно».

Замечу, что в React-Redux-Form есть компонент LocalForm, который позволяет работать без redux, но на мой взгляд, пропадает смысл устанавливать библиотеку размером 21,9kB и использовать её менее чем на половину.

Я не против названных библиотек, в конкретных случаях они незаменимы. Например, когда от введённых данных зависит сторонний компонент, не связанный с формой. Но в своей статье я хочу рассмотреть формы, которые не нуждаются в redux.

Я начал использовать локальный state компонента, при этом возникли новые трудности: увеличилось количество кода, компоненты потеряли читаемость, появилось много дублирования.

Решением проблем стала концепция High Order Component. Если коротко, HOC — это функция, которая получает на вход компонент и возвращает его обновлённым с интеграцией дополнительных или изменённых props-ов. Подробнее о HOC можно почитать на официальном сайте React.js. Цель использования концепции HOC была в разделении компонента на две части, одна из которых отвечала бы за логику, а вторая — за отображение.

Создание формы

В качестве примера создадим простую форму обратной связи, в которой будет 3 поля: имя, email, телефон.

Для простоты используем Create-React-App. Установим его глобально:

затем создадим свое приложение в папке pure-form

Дополнительно установим prop-types и classnames, они нам пригодятся в дальнейшем:

Создадим две папки /components и /containers. В папке /components будут лежать все компоненты, отвечающие за отображение. В папке /containers, компоненты, отвечающие за логику.

В папке /components создадим файл Input.jsx, в котором объявим общий компонент для всех инпутов. Важно на этом этапе не забыть качественно прописать ProptTypes и defaultProps, предусмотреть возможность добавления кастомных классов, а также наследовать его от PureComponent для оптимизации.
В результате получится:

Далее в папке /components создадим файл Form.jsx, в котором будет объявлен компонент, содержащий форму. Все методы для работы с ней будем получать через props, так же как и value для инпутов, поэтому state здесь не нужен. Получаем:

Создание HOC

В папке /containers создадим файл FormWrapper.jsx. Объявим внутри функцию, которая в качестве аргумента получает компонент WrappedComponent и возвращает класс WrappedForm. Метод render этого класса возвращает WrappedComponent с интегрированными в него props. Старайтесь использовать классическое объявление функции, это упростит процесс отладки.

В классе WrappedForm создадим state: isFetching – флаг для контроля асинхронных запросов, data — объект с value инпутов, errors – объект для хранения ошибок. Объявленный state передадим во WrappedComponent. Таким образом реализуется вынос хранилища состояний формы на верхний уровень, что делает код более читаемым и прозрачным.

Но такая реализация не универсальная, потому что для каждой формы придётся создать свою обёртку. Можно усовершенствовать эту систему и вложить HOC внутрь ещё одной функции, которая будет формировать начальные значения state.

В эту функцию можно передавать не только начальные значения state, но вообще любые параметры. Например, атрибуты и методы, на основе которых можно будет создать форму в Form.jsx. Пример такой реализации будет темой для следующей статьи.

В файле Form.jsx объявим начальные значения state и передадим их в HOC:

Создадим метод handleInput для обработки введённых в инпут значений. Он получает event, из которого берём value и name и передаём их в setState. Поскольку значения инпутов хранятся в объекте data, в setState вызываем функцию. Одновременно с сохранением полученного значения обнуляем хранилище ошибки изменяемого поля. Получим:

Теперь создадим метод handeSubmit для обработки формы и выведем данные в консоль, но перед этим необходимо пройти валидацию. Валидировать будем только обязательные поля, то есть все ключи объекта this.state.errors. Получим:

С помощью метода reduce переберём все обязательные поля. При каждой итерации происходит вызов метода validate, в который передаём пару name, value. Внутри метода происходит проверка на корректность введённых данных, по результатам которой возвращается булев тип. Если хотя бы одна пара значений не пройдёт валидацию, то переменная isValid станет false, и данные в консоль не выведутся, то есть форма не будет обработана. Здесь рассмотрен простой случай — проверка на непустую форму. Метод validate:

Оба метода handleSubmit и handleInput необходимо передать во WrappedComponent:

В результате получим готовую форму обратной связи, с простой валидацией и выводом ошибок. При этом мы вынесли логическую часть из компонента, отвечающего за отображение.

Заключение

Итак, мы рассмотрели базовый пример создания HOC для обработки формы. При создании формы использовались только простые инпуты, без сложных элементов, таких как выпадающие списки, чекбоксы, радиобаттоны и прочие. При их наличии, возможно, придётся создавать дополнительные методы обработки событий.

Вопросы и замечания пишите в комментариях к статье или мне на почту.

Готовый пример можно найти здесь: pure react form.

Источник

Создание React форм в 2020 году

Привет, Хабр. Представляю вам перевод статьи «Creating forms in React in 2020» автора Kristofer Selbekk

forms2020

Поля ввода. Текстовые области. Радиокнопки и чекбоксы. Вот некоторые из основных точек взаимодействия, которые мы, как разработчики, имеем с нашими пользователями. Мы размещаем их на сайте, пользователи их заполняют и если нам повезёт, то заполненные формы приходят к нам без ошибок валидации.

Обработка форм является неотъемлемой частью большого количества веб-приложений, и это одна из вещей, которые React делает лучше всего. У вас есть большая свобода для создания и обработки форм. Но есть ли лучший способ сделать это?

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

Помните о правилах хорошего тона

Хотя это не имеет прямого отношения к обсуждаемой теме, я хочу убедиться, что вы не забыли сделать свои формы понятными для всех. Добавьте теги к своим полям ввода, установите правильные aria-атрибуты для случаев, когда ввод недопустим, и структурируйте ваш контент семантически правильно. Это облегчает использование вашей формы как для пользователей, так и для разработчиков.

Обработка форм с использованием State Hook

Для начала давайте посмотрим, как я обычно работаю с состоянием формы. Я сохраняю все поля как отдельные элементы состояния и обновляю их все по отдельности, что выглядит примерно так:

Сначала я создаю две отдельные части состояния — имя пользователя и пароль. Эти две переменные затем передаются в соответствующее поле ввода, определяя значение этого поля. Всякий раз, когда что-то в поле изменяется, мы обязательно обновляем значение состояния, вызывая повторную перерисовку нашего приложения.

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

Создание пользовательского хука

Давайте сделаем небольшой рефакторинг и создадим собственный хук, который немного улучшит наш код:

Мы создаем пользовательский хук useFormField, который создает для нас обработчик события onChange, а также сохраняет значение в состояние формы. В этом случае мы можем использовать наш хук со всеми полями формы.

Обработка большого количества полей

Недостатком этого подхода является то, что он плохо масштабируется по мере роста вашей формы. Для небольших форм, таких как login, это, вероятно, хорошо, но когда вы создаете формы профиля пользователя, вам может понадобиться запросить много информации! Должны ли мы вызывать наш хук снова и снова?

Всякий раз, когда я сталкиваюсь с подобной ситуацией, я склоняюсь к написанию пользовательского хука, который хранит все мои формы в одном большом фрагменте. Это может выглядеть так:

С помощью хука useFormFields мы можем продолжать добавлять поля, не добавляя сложности нашему компоненту. Мы можем получить доступ ко всем состояниям формы в одном месте, а наш код выглядит аккуратно и лаконично. Конечно, вам, вероятно, понадобится использовать setState для некоторых ситуаций, но для большинства форм приведённый приём подойдёт просто отлично.

Альтернативный подход

Таким образом, обработка состояния отлично работает, и в большинстве случаев это предпочтительный подход в React. Но знаете ли вы, что есть другой способ? Оказывается, браузер по умолчанию обрабатывает внутреннее состояние формы, и мы можем использовать это для упрощения нашего кода!

Вот та же форма, но позволяющая браузеру обрабатывать состояние формы:

Посмотрите как просто! Не использовано ни одного хука, нет установки начального значения, отсутствует обработчик onChange. Самое приятное то, что код все еще работает как и прежде — но как?

Вы могли заметить, что мы делаем что-то немного другое в функции handleSubmit. Мы используем встроенный browser API под названием FormData. FormData — это удобный (и хорошо поддерживаемый) способ получения значений из наших полей ввода!

Мы получаем ссылку на форму в DOM через атрибут target события submit и создаем новый экземпляр класса FormData. Теперь мы можем получить все поля по их атрибуту name, вызвав formData.get («имя поля ввода»).

Таким образом, вам никогда не нужно явно обрабатывать состояние формы. Если вам нужны значения по умолчанию (например, если вы изменяете начальные значения полей из базы данных или локального хранилища), React предоставляет вам удобную опцию defaultValue для этого.

Когда лучше использовать каждый подход

Поскольку формы являются неотъемлемой частью большинства веб-приложений, важно знать, как с ними обращаться. И React предоставляет вам множество способов сделать это.
Для простых форм, которые не требуют тщательной проверки (или которые могут полагаться на элементы управления проверкой формы HTML5), я предлагаю вам просто использовать встроенную обработку состояний, которую DOM предоставляет нам по умолчанию. Есть довольно много вещей, которые вы не можете сделать (например, программно изменить входные значения или проверка в реальном времени), но в самых простых случаях (например, поле поиска или поле входа в систему, как указано выше), вам, вероятно, подойдёт наш альтернативный подход с использованием browser API.

Когда вы выполняете пользовательскую проверку или вам нужен доступ к некоторым данным формы перед её отправкой, вам нужно явно обработать состояние с помощью контролируемых компонентов. Вы можете использовать обычные useStateHooks или создать пользовательский хук, чтобы немного упростить ваш код.

Стоит отметить, что разработчики React рекомендуют использовать контролируемые компоненты (явно обрабатывать состояние компонента) в большинстве случаев — поскольку этот подход дает вам большую гибкость в дальнейшем. На мой взгляд, разработчики часто жертвуют простотой ради гибкости, которая им зачастую не нужна.

Какой бы подход вы не решили использовать, обработка форм в React никогда не была такой простой, как сегодня. Вы можете позволить браузеру обрабатывать простые формы, в то же время явно обрабатывая состояние форм, когда того требует ситуация. Надеюсь, приведённые способы, будут вам полезны и помогут решить задачу, сократив количество строк в вашем коде.

Источник

2.10 Формы

Работа элементов HTML-форм в React немного отличается от работы других DOM-элементов. Это связано с тем, что элементы форм по своей природе обладают некоторым внутренним состоянием. К примеру, данная форма в нативном HTML принимает только имя:

Представленная форма имеет поведение HTML-формы по умолчанию: просмотр новой страницы, когда пользователь посылает форму. Если такое поведение вам необходимо и в React, то оно работает как обычно. Но в большинстве случаев нам удобно иметь JavaScript-функцию, которая имеет доступ к данным, которые пользователь ввел в форму и обрабатывает её отправку. Для этой цели, есть стандартный подход, под названием «контролируемые компоненты».

2.10.1 Контролируемые компоненты

Также в атрибут value вы можете передать массив. Это позволяет выбрать в теге select сразу несколько опций.

2.10.4 Тег input типа file

В нативном HTML тег позволяет пользователю выбирать один или несколько файлов из хранилища своего устройства для загрузки на сервер, а также манипулировать собой с помощью JavaScript через File API.

Поскольку его значение доступно только для чтения, это неконтролируемый компонент в React. Он обсуждается вместе с другими неконтролируемыми компонентами позже в документации.

2.10.5 Обработка множества input

Обратите внимание на то, как мы использовали синтаксис ES6 вычисляемого имени свойства, чтобы обновить ключ состояния в соответствии с данным именем тега input :

Это эквивалент данного ES5 кода:

Поскольку setState() делает слияние частичного состояния в текущее автоматически, нам лишь нужно вызывать его с изменившейся частью.

2.10.5 Пустое значение атрибута value контролируемого input

Следующий код демонстрирует это. (Сначала input заблокирован, но становится редактируемым после короткой задержки.)

2.10.6 Альтернативы контролируемым компонентам

Источник

React: немного о работе с формами

image loader

В последнее время мне на глаза часто попадаются статьи, посвященные работе с формами в React и разработке соответствующих кастомных хуков. Вот парочка таких статей:

Сначала мы разработаем хук, затем используем его в формах для регистрации и авторизации.

Для большей правдоподобности мы напишем простой express-сервер, который будет возвращать некоторые пользовательские данные (например, jwt-токен и хешированный пароль), а также некоторые типичные для процесса авторизации ошибки (например, 404 User not found или 409 Email already in use ).

При разработке хука и компонентов приложения мы применим несколько продвинутых паттернов, которые, смею надеяться, покажутся вам интересными.

Исходный код проекта находится здесь.

Возможно, для того, чтобы в песочнице все заработало, потребуется ввести команду yarn dev в терминале.

Разработка хука

Обратите внимание: хук, который мы с вами реализуем, предназначен для работы с формами небольших и, возможно, средних размеров. Если в ваша форма содержит 100 полей (условно), вероятно, вам лучше присмотреться к React Hook Form, Formik или другим аналогичным решениям.

Давайте начнем с определения того, какие пропы должен принимать наш хук.

Приступаем к реализации.

Функция для обеззараживания введенных пользователем данных и удаления из них лишних пробелов может выглядеть так:

А функция для проверки заполненности обязательных полей так:

Начинаем писать хук:

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

Обратите внимание: утилита very-simple-fetch спроектирована таким образом, что в объект ответа включается не только успешный ответ (свойство data ), но также кастомные ошибки и исключения (например, полученные в результате res.status(400).json(< message: 'Custom error' >) или throw new Error(‘Exception’) ; свойство error ). Также объект ответа содержит дополнительную информацию, в частности статус-код ответа, который мы будем использовать для определения характера ошибки, возникшей на сервере, в соответствующем компоненте приложения (свойство info ).

Таким образом, последняя строка реализации хука будет выглядеть следующим образом:

Для реализации хука мы будем использовать только 2 основных React-хука. Импортируем их в начале файла:

Импортируем ее после React-хуков и экспортируем для обеспечения возможности прямого использования (мы воспользуемся этим для определения URL сервера с помощью сеттера simpleFetch.baseUrl ):

Для выполнения валидаторов ( validators ) над соответствующими инпутами с выбором соответствующих сообщений об ошибках ( messages ) нам требуется некоторая общая функция валидации. Эту функцию лучше вынести за пределы хука, во избежание ее создания при каждом рендеринге. Конечно, мы могли бы просто мемоизировать ее с помощью useCallback с пустым массивом зависимостей, но это привело бы к неоправданным дополнительным расходам на производительность.

Размышляя о сигнатуре данной функции, я посчитал хорошей идеей реализовать в ней автоматическую проверку совпадения значений полей с их парами для подтверждения (например, password и confirmPassword ). Функция также должна учитывать, что поля, для которых в validators отсутствуют валидаторы и которые не имеют пар для подтверждения, всегда являются валидными. Вот как она может выглядеть:

Теперь можно по-настоящему приступить к реализации.

Начнем с определения начальных значений:

В качестве побочного эффекта при каждом изменении значения любого поля мы проверяем заполненность обязательных полей и на основе этого переключаем индикатор disabled :

Функция изменения значения поля:

Функция для отправки формы:

Наконец, реализуем функцию для сброса формы:

Пожалуй, это все, что нам нужно для обработки форм.

У вас может возникнуть два вопроса:

Подготовка проекта и реализация сервера

Формируем общую структуру проекта:

Находясь в корневой директории, инициализируем проект и устанавливаем общую зависимость:

Определяем команду для запуска серверов в package.json:

Как видите, у нас все серьезно. Мы реализуем фиктивный, но довольно близкий к реальному сервис для аутентификации.

Определяем команды для запуска сервера в server/package.json :

Создаем в директории server файл index.js следующего содержания:

Реализация фронтенда

Находясь в корневой директории, создаем шаблон React-приложения с помощью [ create-react-app ]() и устанавливаем 2 дополнительные зависимости:

Структура нашего React-приложения будет такой:

Немного поправим стили в src/index.css :

Проксируем запросы в package.json :

Начнем с основных файлов.

Тут все стандартно.

В App.js мы делаем следующее:

Тоже ничего особенного.

В components/Login.js мы делаем следующее:

Проверка работоспособности

Пришло время проверить работоспособность нашего хука и формы.

Эта команда запускает серверы и открывает вкладку браузера по адресу http://localhost:3000 :

image loader

Переходим на страницу аутентификации:

image loader

image loader

Видим, что кнопка для отправки формы осталась заблокированной. Находим ее в разделе Elements инструментов разработчика и удаляем у нее атрибут disabled :

image loader

Видим, что кнопка стала активной. Нажимаем ее и… получаем сообщение You need to enable JavaScript to run this app. :

image loader

Вводим невалидный email и какой-нибудь пароль (кроме test ), нажимаем Enter или кнопку Login :

image loader

Получаем сообщение от клиента (хука) о неправильном email.

image loader

Получаем сообщение от сервера о неправильных данных для авторизации.

Вводим test в поле для пароля:

image loader

Получаем результат с токеном.

Парочка скриншотов с формой для регистрации.

Значение поля для подтверждения пароля не совпадает со значением поля для пароля:

image loader

Пользователь с таким email уже зарегистрирован:

image loader

image loader

Заключение

Не люблю писать заключения, поэтому не буду.

Надеюсь, что вы не зря потратили время и нашли для себя что-то интересное.

Любая конструктивная критика приветствуется. Любые замечания и предположения по улучшению хука в форме личных сообщений или пул-реквестов непременно будут учтены в будущих версиях пакета.

Источник

Формы

Элементы формы HTML работают немного иначе, чем другие элементы DOM в React, потому что элементы формы по своей реализации сохраняют некоторое внутреннее состояние. Например, эта форма в обычном HTML принимает только имя:

У этой формы есть поведение HTML-формы по умолчанию — переход на новую страницу при отправке пользователем формы. Если вы хотите такое поведение в React, это будет просто работать и так. Но в большинстве случаев удобно создать JavaScript-функцию, которая будет обрабатывать отправку формы и иметь доступ к данным, которые ввёл пользователь в форму. Общепринятый способ достичь этого — использование техники под названием «контролируемые компоненты».

Мы можем объединить всё это вместе, сделав состояние React «единственным источником данных (истины)». Затем компонент React, который отрисовывает форму, также контролирует, что происходит в этой форме при последующем вводе данных пользователем. Элемент поля ввода формы, значение которого контролируется React подобным образом, называется «контролируемым компонентом».

Например, если мы хотим, чтобы предыдущий пример выводил на консоль имя при отправке формы, мы можем написать её как контролируемый компонент:

В контролируемом компоненте каждое изменение состояния будет связано с функцией-обработчиком. Это упрощает изменение или проверку входных данных пользователя. Например, если мы хотим, чтобы входные имена записывались заглавными буквами, мы могли бы написать handleChange таким образом:

определяет свой текст по дочерним элементам:

используется атрибут value вместо этого. Таким образом, форма, использующая

, может быть написана очень похоже на форму, которая использует обычное однострочное поле ввода:

Обратите внимание, что this.state.value создаётся в конструкторе, так что текстовая область начинается с текста, определённого в нём.

В HTML создаёт выпадающий список. Например, этот HTML создаёт выпадающий список вкусов:

Тег поля для загрузки файла

В HTML элемент позволяет пользователю выбрать один или несколько файлов из устройства хранения для загрузки на сервер или изменять его с помощью JavaScript через API File.

Поскольку его значение доступно только для чтения, это неконтролируемый компонент в React. Он обсуждается вместе с другими неконтролируемыми компонентами позднее в этой документации.

Обработка нескольких полей ввода

Обратите внимание, что мы использовали синтаксис вычисляемого имени свойства из ES6 для обновления ключа состояния, соответствующему определённому имени поля ввода:

Это эквивалентно этому коду в ES5:

Кроме того, поскольку setState() автоматически объединяет частичное состояние в текущее состояние, нам нужно только вызвать его с изменёнными частями.

Значение null в контролируемом компоненте

Код ниже демонстрирует такой случай. (Сначала поле ввода заблокировано, но становится редактируемым после короткой задержки.)

Альтернативы контролируемым компонентам

Иногда бывает сложно использовать контролируемые компоненты, потому что нужно писать обработчик событий для каждого способа, которым ваши данные могут измениться, и передать всё входное состояние через React-компонент. Это может стать особенно раздражающим, когда вы преобразуете ранее существовашую базу кода на React или интегрируете приложение React с библиотекой, отличной от React. В таких ситуациях вы можете рассмотреть использование неконтролируемых компонентов, альтернативный метод реализации форм с полями ввода.

Полноценные готовые решения

Если вы ищете готовое решение, включающее валидацию, отслеживание заполненных полей и обработку отправки формы, то Formik — один из популярных вариантов. Однако, этот инструмент создан с использованием тех же принципов контролируемых компонентов и управления состоянием, поэтому обязательно изучите их.

Источник

Понравилась статья? Поделить с друзьями:
Добавить комментарий
  • Как сделать успешный бизнес на ритуальных услугах
  • Выездной кейтеринг в России
  • Риски бизнеса: без чего не обойтись на пути к успеху
  • react модальное окно с формой
  • react клиент серверное приложение