Как отправить файл на сервер react

Обновлено: 11.07.2024

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

Предварительные знания: Базовая компьютерная грамотность, понимание HTML и базовые знания по HTTP и программированию на стороне сервера.
Задача: Понять, что происходит при отправке данных формы, в том числе получить представление о том, как данные обрабатываются на стороне сервера.

Куда отправляются данные?

Здесь мы обсудим, что происходит с данными при отправке формы.

О клиентской/серверной архитектуре

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

На стороне клиента: определение способа отправки данных

Элемент <form> определяет способ отправки данных. Все его атрибуты предназначены для того, чтобы вы могли настроить запрос на отправку, когда пользователь нажимает кнопку отправки. Двумя наиболее важными атрибутами являются action и method .

Атрибут action

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

Здесь мы используем относительный URL - данные отправляются на другой URL на сервере:

Если атрибуты не указаны, как показано ниже, данные из формы <form> отправляются на ту же страницу, на которой размещается данная форма:

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

Атрибут method

Метод GET

Рассмотрим следующую форму:


Данные добавляются в URL как последовательность пар имя / значение. После того, как URL веб-адрес закончился, мы добавляем знак вопроса ( ? ), за которым следуют пары имя / значение, каждая из которых разделена амперсандом ( & ). В этом случае мы передаём две части данных на сервер:

  • say , со значением Hi
  • to , со значением Mom

Примечание: вы можете найти этот пример на GitHub — смотрите get-method.html (see it live also).

Метод POST

Давайте рассмотрим пример — это та же самая форма, которую мы рассматривали в разделе GET выше, но с атрибутом method , установленным в post .

Заголовок Content-Length указывает размер тела, а заголовок Content-Type указывает тип данных, отправляемых на сервер. Мы обсудим эти заголовки позже.

Примечание: вы можете найти этот пример на GitHub — смотрите post-method.html (see it live also).

  1. Нажмите F12
  2. Выберите Network
  3. Выберите "All"
  4. Выберите "foo.com" во вкладке "Name"
  5. Выберите "Headers"

Затем вы можете получить данные формы, как показано на рисунке ниже.


Единственное, что отображается пользователю — вызываемый URL. Как упоминалось раннее, запрос с методом GET позволит пользователю увидеть информацию из запроса в URL, а запрос с методом POST не позволит. Две причины, почему это может быть важно:

На стороне сервера: получение данных

Пример: Чистый PHP


Пример: Python

Этот пример показывает, как вы можете использовать Python для решения той же задачи — отобразить отправленные данные на странице. В этом примере используется Flask framework для визуализации шаблонов, поддерживающих форму отправки данных (смотри python-example.py).

Два шаблона из коде выше взаимодействуют так:

    : Та же форма, что и выше The POST method , только с использованием action к > . (Это Jinja2 шаблон, который изначально HTML, но может содержать вызовы Python кода в фигурных скобках, которые запустятся веб-сервером. url_for('hello') буквально говорит: после отправки данных переадресуй их в /hello .) : Этот шаблон просто содержит строку, которая отображает два бита данных, переданных ему при отображении. Это сделано с помощью функции hello() , указанной выше, которая выполняется, когда запрос направляется в /hello URL.

Примечание: Опять же, этот код не будет работать, если вы просто попробуете загрузить его прямо в браузер. Python работает немного иначе, чем PHP — чтобы запустить этот код, нужно установить Python/PIP, потом установить Flask используя команду: pip3 install flask . После этого, вы сможете запустить файл из примера, используя команду: python3 python-example.py , потом открыть localhost:5000 в своём браузере.

Другие языки и фреймворки

    для Python (немного тяжеловеснее, чем Flask, но больше инструментов и опций) для Node.js для PHP для Ruby для Elixir

Стоит отметить, что использование фреймворков и работа с формами - это не всегда легко. Но это намного легче, чем пытаться написать аналогичную функциональность с нуля, и это определённо сэкономит время.

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

Особый случай: отправка файлов

Атрибут enctype

Этот атрибут позволяет конкретизировать значение в Content-Type HTTP заголовок, включённый в запрос, при генерировании отправки формы. Этот заголовок очень важен, потому что указывает серверу, какой тип данных отправляется. По умолчанию это: application/x-www-form-urlencoded . На человеческом это значит: "Это форма с данными, которые были закодированы в URL параметры."

  • Указать method атрибут POST , поскольку содержимое файла, как и сам файл, не могут быть отображены в URL параметрах.
  • Установить в enctype значение multipart/form-data , потому что данные будут разбиты на несколько частей: одна часть на файл (две части на два файла), и одна часть на текстовые данные (при условии, если форма содержит поле для получения тестовых данных).
  • Подключите один или более File picker виджетов, чтобы позволить своим пользователям выбрать, какие и сколько файлов будут загружены.

Примечание: Некоторые браузеры поддерживают multiple атрибут элемента <input> , который позволяет выбрать больше одного файла для загрузки, при использовании одного элемента <input> . То, как сервер работает с этими файлами, напрямую зависит от технологий, используемых на сервере. Как упоминалось ранее, использование фреймворков сделает вашу жизнь намного легче.

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

Проблемы безопасности

Каждый раз, когда вы отправляете данные на сервер, вы должны учитывать безопасность. HTML-формы являются наиболее распространёнными векторами атак на серверы(места, где могут происходить атаки). Проблемы вытекают не из самих форм HTML, а из-за того, как сервер обрабатывает данные из этих форм.

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

XSS "Межсайтовый скриптинг" и CSRF "Подделка межсайтовых запросов"

Межсайтовый скриптинг (XSS "Cross Site Request Forgery") и подделка межсайтовых запросов (CSRF "Cross-Site Scripting") - это распространённые типы атак, которые происходят при отображении данных после ответа сервера или другого пользователя.

Межсайтовый скриптинг (XSS "Cross Site Request Forgery") позволяет злоумышленникам внедрить клиентский скрипт в веб-страницы, просматриваемые другими пользователями. Подделка межсайтовых запросов (CSRF "Cross-Site Scripting") может использоваться злоумышленниками для обхода средств контроля доступа, таких как одна и та же политика происхождения. Последствие от этих атак может варьироваться от мелких неудобств до значительного риска безопасности.

CSRF-атаки аналогичны XSS-атакам в том, что они начинаются одинаково - с внедрения клиентского скрипта в веб-страницы - но их конечные цели разные. Злоумышленники CSRF пытаются назначить права пользователям с более высоким уровнем прав доступа(например, администратору сайта), чтобы выполнить действие, которое они не должны выполнять (например, отправка данных ненадёжному пользователю). Атаки XSS используют доверие пользователя к веб-сайту, в то время как атаки CSRF используют доверие веб-сайта к пользователю.

Чтобы предотвратить эти атаки, вы всегда должны проверять данные, которые пользователь отправляет на ваш сервер, и (если вам нужно отобразить их) стараться не отображать HTML-контент, предоставленный пользователем. Вместо этого вы должны обработать предоставленные пользователем данные, чтобы не отображать их слово в слово. Сегодня почти все платформы на рынке реализуют минимальный "фильтр", который удаляет элементы HTML <script> , <iframe> (en-US) и <object> (en-US) полученных от любого пользователя. Это помогает снизить риск, но не исключает его полностью.

SQL - вброс

SQL -вброс представляет собой тип атак, при которых осуществляется попытка выполнения действия с базой данных, используемой целевым веб-сайтом. В этих случаях обычно осуществляется отправка SQL-запроса в надежде, что сервер выполнит этот запрос (обычно при попытке сервера приложения сохранить данные, отправляемые пользователем). Данный вид атак является одним из самых направленных атак на веб-сайты.

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

Такие атаки являются самыми незаметными, но при этом могут превратить ваш сервер в зомби.

Будьте параноиком: никогда не доверяйте вашим пользователям

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

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

  • Избегайте потенциально опасных символов. Конкретные символы, с которыми следует соблюдать осторожность, зависят от контекста, в котором используются данные, а также от используемой платформы. Однако, все языки на стороне сервера имеют соответствующие функции для обеспечения такой защиты.
  • Ограничьте входящий объем данных для поступления только реально необходимых данных.
  • Помещайте загруженные файлы в песочницу (храните их на другом сервере и предоставляйте доступ к фалам только через отдельный поддомен или даже через совершенно другое доменное имя).

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

Примечание: В статье Безопасность веб-сайта нашего раздела серверного обучения приведено подробное обсуждение упомянутых угроз и возможных способов их устранения.

Заключение

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

Смотрите также

Если вы хотите узнать больше об обеспечении безопасности веб-приложений, вы можете использовать следующие источники информации:

От автора: если вы новичок в веб-разработке, асинхронная загрузка файлов может показаться сложной задачей. Но по сути, это еще один запрос AJAX API. Если вас не просят оптимизировать меди файлы на стороне клиента или выполнить некие проверки целостности, это легко сделать. В этом уроке я расскажу в загрузке файлов через AJAX из front end React, так как React – одна из популярнейших библиотек представлений на данный момент. Для работы с сервером мы обсудим вариант с Node.js и CDN.

Необходимые условия

Код проекта доступен в моем репозитории на Github. Или же вы можете начать с нуля и следовать шагам.

Необходимо настроить Node.js, если это еще не сделано. Далее с помощью NPM нужно установить React.js и зависимые библиотеки. Я буду использовать create-react-app для шаблона React.


JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

Далее в уроке будем делать AJAX запросы через axios. Рекомендую установить его.

Для создания настраиваемого экспресс сервера будем использовать express-generator . Его можно использовать как стартовую точку для back end.

Я установлю пару дополнительных пакетов:

nodemon – для слежки за изменениями в файлах

express-fileupload – для упрощения загрузки файлов

Ниже представлена измененная версия app.js. Мы всего лишь добавили cors и express-fileupload.

app . use ( '/public' , express . static ( __dirname + '/public' ) ) ; res . locals . error = req . app . get ( 'env' ) === 'development' ? err : < >; var port = normalizePort ( process . env . PORT || ‘ 8000 ’ ) ;

Структурирование компонентов React

React использует компоненты для создания UI. Файл index.js в forms/src является стартовой точкой. Он монтирует компонент приложения и проводит его рендер. Замените код в файле App.js:


JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

Загрузка файлов через HTML5 загрузчик

Для этого способа есть библиотека react-dropzone, встроенная в React. Для рендера зоны HTML5 Drag ’n’ Drop можно использовать компонент Dropzone. После установки библиотеки через yarn добавьте react-dropzone. Вы сможете делать такие вещи:

< div > Try dropping some files here , or click to select files to upload . < / div >

Для обновления состояния или посылки AJAX запроса на загрузку файла необходимо написать метод onDrop.

Или можно использовать традиционный метод, а также их смесь.

Традиционная загрузка файлов через формы

Традиционный загрузчик файлов использует тег input с type=”file” и необязательный интерфейс FormData. Наша форма:

< input className = "form-control" ref = < ( ref ) = > < this . fileName = ref ; >> type = "text" placeholder = "Optional name for the file" / > < button className = "btn btn-success" type > Upload < / button >

Мы еще не определили метод handleUpload. handleUpload делает API запросы на сервер, и если запрос успешен, устанавливает состояние, чтобы пользователь понял, что запрос прошел успешно.

this . handleUploadImage = this . handleUploadImage . bind ( this ) ;

Разберем код. Сначала мы создаем объект FormData и наполняем его парами ключ/значение из данных формы. Далее с помощью axios мы делаем запрос POST AJAX на сервер. Если все хорошо, сервер возвращает тело файла, с помощью которого можно сформировать ссылку на изображение.

Создание экспресс сервера для обработки запросов

Если нажать на кнопку Submit, в консоли появится ошибка, так как мы еще не настроили сервер для принятия POST запросов. Я буду обрабатывать загрузку файлов через библиотеку express-fileupload. Мы уже установили ее ранее.

Добавьте код ниже в файл app.js экспресс сервера.

Мы создали новый экспресс промежуточный слой. Промежуточный слой срабатывает, когда запрос пытается получить доступ к ресурсу ‘/upload’. Функция этого слоя имеет доступ к 3 объектам req, res и next. В объекте req хранится наш файл и его название.

Далее мы присваиваем файл объекту fileUpload. Файл сохраняется в публичной папке. Если есть какие-то ошибки, мы вернем код 500. Иначе сервер вернет путь к файлу.

Загрузка файла на CDN

Прямо сейчас мы разместим файлы в публичной директории. Это будет работать для нашего приложения, но для большинства реальных сценариев это будет не так идеально. Файлы можно сохранить в базу данных или загрузить на CDN типа Cloudinary или Amazon S3. Если вы работает с изображениями, то можно воспользоваться техниками оптимизации изображений на CDN для уменьшения размера изображений без существенной потери качества. В серверный код необходимо добавить вызов axios:

мой файл App.js (front-end)

и мой файл server.js (back-end)

Кто-нибудь может мне помочь, пожалуйста ? Спасибо!

3 ответа

У меня два сервера. Первый (основной) - это сервер, на котором установлен скрипт и база данных. Второй (удаленный) - это сервер, на который загружены только файлы (только для хранения). Теперь я запутался в том, как загрузить файлы, и у меня есть 2 идеи, чтобы сделать это, и я не знаю, являются ли.

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

Вы можете использовать axios для загрузки файла.

Теперь вам нужно добавить его в данные формы.

В вашем приложении NodeJS:

В вашем интерфейсе возьмите свой файл

Как только вы настроите FormData, вы можете позвонить с axios.

Затем вам нужно установить пакет multer на стороне сервера $npm i -S multer, затем в вашем файле server.js.

Вы можете настроить multer только в самом начале, после того, как все это потребуется.

Затем в вашем маршруте:

Надеюсь, это поможет.

Тогда для express вам следует посмотреть на multer , который является промежуточным программным обеспечением для обработки multipart/form-data.

Мне трудно найти ресурсы, которые объясняют, как подключить webpack к приложению express server. Я хочу использовать webpack для babel, чтобы использовать es6 при написании react и использовать его горячий модуль и cheap-module-source-map. Но webpack запускает свой собственный экспресс-сервер, и в.

Загрузите файл изображения и преобразуйте его в zip на стороне клиента, а затем загрузите ( преобразованный zip ) файл на сервер. Существует js jsZip , который может конвертировать файл изображения в zip на стороне клиента, но вопрос в том, как я могу загрузить этот преобразованный файл zip.

Похожие вопросы:

Я хочу, чтобы пользователь мог просматривать свои локальные файлы, выбирать файл json и загружать его. Я не хочу импортировать его напрямую. После этого я отправлял его на какой-нибудь сервер api и.

Как лучше всего войти в систему пользователя: 1) сначала получите hash пароля с javascript, отправьте его на сервер, а затем сравните его с hash, хранящимся в базе данных. 2) отправьте пароль в виде.

У меня два сервера. Первый (основной) - это сервер, на котором установлен скрипт и база данных. Второй (удаленный) - это сервер, на который загружены только файлы (только для хранения). Теперь я.

я очень уверен , что вы, ребята, видели функцию записи whats app, поэтому я хочу сделать модуль очень похожим на этот, я делаю это приложение в react native надеюсь, что вы, ребята, предоставите мне.

Мне трудно найти ресурсы, которые объясняют, как подключить webpack к приложению express server. Я хочу использовать webpack для babel, чтобы использовать es6 при написании react и использовать его.

Загрузите файл изображения и преобразуйте его в zip на стороне клиента, а затем загрузите ( преобразованный zip ) файл на сервер. Существует js jsZip , который может конвертировать файл изображения.

мое приложение react работает на localhost:3000 а мой экспресс-сервер работает на localhost:1234 это мой экспресс сервер: const express = require(express) const cors = require(cors) const app =.


Первоначальная настройка проекта

Решая эту проблему, мы собираемся использовать экспресс-пакет в качестве нашего веб-сервера и использовать метод React renderToString () для визуализации всех компонентов на стороне сервера.

server.js: получить данные и отобразить веб-страницу.

server.js: Извлеките данные и визуализируйте веб-страницу.

Мы передаем все состояние клиентской стороне через тег скрипта в html-документе, используя функцию serialize () в пакете serialize-javascript. (Этот парсер javascript позволяет нам анализировать больше типов объектов, таких как Date, поэтому я бы рекомендовал использовать этот пакет вместо функции JSON.stringify ().) На стороне клиента мы можем читать объект window.initialState и анализировать его в магазин Redux.

render.js: сериализуйте начальное состояние и проанализируйте его с помощью объекта window.initialState в теге скрипта для наших клиентов.

Пошаговый рендеринг на стороне сервера в React

С помощью этих шагов мы можем предварительно загрузить и проанализировать состояние для клиента. Но что нам нужно для предварительной загрузки этой страницы?

Разберем сложность на несколько задач

Разбиение сложности на компоненты

Идеальное место, чтобы решить, какие данные нам нужны, и получить данные на стороне клиента - это метод componentDidMount (). Таким образом, мы можем начать выборку сразу после того, как компонент был смонтирован, или пропустить выборку, если данные уже доступны в магазине.

Когда мы копируем эту логику на сервер, мы дублируем логику в двух отдельных частях приложения. Компонент и функция рендеринга на стороне сервера. Еще более проблематично то, что мы объединяем логику всех компонентов в одну функцию и делаем файл излишне сложным. У каждого компонента есть свой собственный набор правил, отображать ли дочерний компонент, поэтому эта функция будет значительно расширяться в будущем. Разработчику практически невозможно определить в этой единственной функции, какие данные требуются во всех наших вложенных компонентах, и поддерживать их в будущем. И когда к команде присоединяется новый разработчик, есть большая вероятность, что он или она, вероятно, отредактируют компонент, но также забудут обновить наше дерево решений на стороне сервера. Мы не хотим, чтобы это произошло. Итак, давайте займемся проблемой номер 1 и перенесем эту сложность подальше от сервера.

Есть всего две проблемы:

  1. Метод didComponentMount () никогда не вызывается, когда мы используем функцию renderToString () React. Поэтому нам нужно вызвать метод didComponentMount () со стороны сервера самостоятельно.
  2. Нам нужно вызвать этот метод перед выполнением renderToString (), потому что функции renderToString () требуется хранилище с предварительно выбранными данными. Поскольку на этом этапе у нас нет сконструированных компонентов React, нам нужно сделать метод в наших компонентах React статическим.

Итак, давайте займемся проблемой номер 2 и сделаем этот метод доступным на стороне сервера. Мы делаем это, перемещая код в новый статический метод preInitStore (). Таким образом, мы можем выполнить его с помощью кода App.preInitStore () со стороны сервера.

Устранение ограничений статического метода

… Теперь мы можем выполнить это в нашем методе preInitStore ():

Самостоятельная отправка создателя действия fetchGeneral в статическом методе preInitStore ()

Теперь у нас есть метод, который мы можем вызывать со стороны сервера, в то время как вся логика находится в самом компоненте.
(Примечание: поскольку теперь у нас есть статический метод в нашем компоненте, мы также можем совместно использовать другие статические методы между серверным и клиентским кодом внутри компонента.)

Подождем ответа

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

С этой модификацией вызывающий метод App.preInitStore () может ждать, пока данные не будут получены из API и сохранены в хранилище.

Решаем все наши задачи!

А теперь пришло время объединить кусочки головоломки, чтобы мы могли решить задачу номер 3! Когда мы ожидаем всех методов dispatch () в дочерних компонентах, компонент App теперь может ожидать метод preInitStore () в дочерних компонентах.

Ожидание выборки в дочерних компонентах с помощью ключевого слова await

И поскольку мы ожидаем действия fetchGeneral () в компоненте App перед тем, как выполнить метод дочерних компонентов preInitStore (), мы также решили проблему номер 3! Поскольку дочерние компоненты могут получить эти данные с помощью метода store.getState ().

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

(Совет: метод приложения preInitStore () теперь отвечает за вызов методов дочерних компонентов preInitStore (). Таким образом, в случае react маршрутизатора это было бы идеальным местом, чтобы решить, какой компонент инициализировать, проверив URL-адрес с экспресс-веб-сервера. См. Полный пример проекта GitHub.)

Теперь мы переместили серверный код в компоненты. Но метод preInitStore () никогда не используется на стороне клиента. Мы можем оптимизировать это, чтобы сэкономить немного байтов для наших посетителей, используя плагин webpack-strip-block для веб-пакетов. Давайте настроим этот плагин таким образом, чтобы он удалял любой код, помеченный как SERVERSIDE-ONLY, чтобы он был удален из нашего последнего клиентского пакета.

Теперь мы можем исключить наши методы preInitStore () из клиентского пакета, добавив 2 комментария:

Заключение

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

Надеюсь, мне удалось сделать ваши серверные веб-сайты более удобными в обслуживании. Если у вас есть вопросы или вы хотите попробовать это самостоятельно, вы можете ознакомиться с полным решением на GitHub по ссылке ниже. В нем также есть пример react-router.

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

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

В HTML элементы формы, такие как <input> , <textarea> и <select> , обычно сами управляют своим состоянием и обновляют его когда пользователь вводит данные. В React мутабельное состояние обычно содержится в свойстве компонентов state и обновляется только через вызов setState()

Мы можем скомбинировать оба подхода и сделать состояние React-компонента «единственным источником правды». Тогда React-компонент будет рендерить форму и контролировать её поведение в ответ на пользовательский ввод. Значение элемента формы input в этом случае будет контролировать React, а сам элемент будет называться «управляемый компонент».

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

Мы установили атрибут value для поля ввода, и теперь в нём всегда будет отображаться значение this.state.value . Состояние React-компонента стало «источником истины». А так как каждое нажатие клавиши вызывает handleChange , который обновляет состояние React-компонента, значение в поле будет обновляться по мере того, как пользователь печатает.

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

HTML-элемент <textarea> в качестве текста отображает дочерний элемент:

В React <textarea> использует атрибут value . Таким образом, форму с <textarea> можно написать почти тем же способом, что и форму с однострочным <input> :

Обратите внимание, что мы инициализировали this.state.value в конструкторе, так что в текстовой области изначально есть текст.

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

Пункт списка «Кокос» выбран по умолчанию из-за установленного атрибута selected . React вместо этого атрибута использует value в корневом теге select . В управляемом компоненте так удобнее, потому что обновлять значение нужно только в одном месте ( state ). Пример:

Подводя итог, <input type="text"> , <textarea> , и <select> работают очень похоже. Все они принимают атрибут value , который можно использовать, чтобы реализовать управляемый компонент.

Примечание

В атрибут value можно передать массив, что позволит выбрать несколько опций в теге select :

В HTML <input type="file"> позволяет пользователю выбрать один или несколько файлов для загрузки с устройства на сервер или управлять им через JavaScript с помощью File API.

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

Обработка нескольких элементов input

Если вам нужны несколько управляемых элементов input , вы можете назначить каждому из них атрибут name , что позволит функции-обработчику решать, что делать, основываясь на значении event.target.name .

Обратите внимание, что мы используем вычисляемые имена свойств, чтобы обновить значение в state через ключ, который соответствует атрибуту name элемента input:

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

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

Если установить управляемому компоненту проп value , то пользователь не сможет изменить его значение без вашего желания. Если вы установили value , а поле ввода по-прежнему можно редактировать, то, возможно, вы случайно задали value , равный undefined или null .

Код ниже это демонстрирует. (Изначально заблокированный input становится редактируемым после небольшой задержки.)

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

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

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

Читайте также: