Handlesubmit что это
Перейти к содержимому

Handlesubmit что это

  • автор:

redux-form

redux-form – библиотека для более быстрого и просто создания различных форм и управления ими.

Установка:

npm install —save redux-form

yarn add redux-form

Как подключить?

  1. В файле, где мы создавали точку входа редьюсеров (т.е. объединяли их при помощи combineReducers) делаем импорт
    import < reducer as formReducer >from ‘redux-form’
  2. Внутри этого combineReducers, где названия редьюсеров присваивались каким-то ключам, добавляем строчку
    form: formReducer Выгдеть это будет примерно так:
let reducers = combineReducers(< profilePage: profileReducer, dialogsPage: dialogsReducer, sidebar: sidebarReducer, usersPage: usersReducer, auth: authReducer, form: formReducer >);

import < reduxForm, Field, reset >from ‘redux-form’;

import React from 'react'; import < reduxForm, Field, reset >from 'redux-form'; const LoginForm = (props) => < return ( 
//здесь идет чистый код нашей формы
) > const LoginReduxForm = reduxForm()(LoginForm) const Login = (props) => < return

LOGIN

> export default Login;

На самом деле reduxForm – это не HOC, а функция, которая запускает его создание.

Как пользоваться?

  1. Все поля в форме меняем на компоненты Field, которые пришли к нам из библиотеки, с указанием component аналогично пропсам. Button не трогаем.
    Было до:
const LoginForm = (props) => < return ( 
name= />
name= />
name= />remember me
) >
const LoginForm = (props) => < return ( 
name= component= />
name= component= />
remember me
) >

Все. Теперь при вводе текста в форме в нашем стейте появляется временный объект login (имя нашей формы), который содержит много объектов, свойствами которых являются наши поля (берутся по name). Среди них объекты “было ли посещено поле”, “было ли тронуто” и т.д. А также объект values, где в свойства (берутся по name) попадает вводимый текст.

Объект reduxForm

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

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

const LoginForm = (props) => < return ( > .

Это мы видим выше код вызова самой компоненты с формой еще без оборачивания. В нее в пропсах и пришел handleSubmit.

const Login = (props) => < const onSubmit = (formData) => < console.log(formData); //здесь мы получаем данные с формы и будем из диспатчить потом dispatch(reset("login")); // очищаем форму >return 

LOGIN

/>
>

Пример передачи даных с формы в ее временный стейт при помощи redux-form

В примере мы двигаемся “снизу в верх” – с вывода формы до передачи данных в стейт.

    Вывод формы и подключение reduxForm к ней:

import React from 'react'; import s from './MyPosts.module.css'; import Post from './Post/Post'; import < reduxForm, Field, reset >from 'redux-form'; //презентационная компонента, в которую встраивается форма const MyPosts = (props) => < let onAddPost = (e, dispatch) => < props.addPost(e.newPostBody); dispatch(reset("profileAddPostForm")); >return ( 
>

My posts

/>
) > //компонента с формой const AddPostForm = (props) => < return (
>
) > //применяем reduxForm к компоненте с формой и получаем новую особую компоненту const AddPostFormRedux = reduxForm() (AddPostForm); export default MyPosts;
import React from 'react'; import from '../../../redux/profile-reducer' ; import MyPosts from './MyPosts'; import < connect >from 'react-redux'; const mapStateToProps = (state) => < return < posts: state.profilePage.posts, newPostText: state.profilePage.newPostText >> //вот здесь происходит диспатч const mapDispatchToProps = (dispatch) => < return < addPost: (newPostText) =>dispatch(addPostActionCreator(newPostText)) > > const MyPostsContainer = connect(mapStateToProps, mapDispatchToProps) (MyPosts); export default MyPostsContainer;
import < usersAPI, profileAPI >from "../api/api"; const ADD_POST = 'ADD-POST'; //в массиве posts примеры постов, которые мы добавляем еще туда let initialeState = < posts: [ , , , , , , ], >; //создаем новый пост в переменной newPost и добавляем const profileReducer = (state = initialeState, action) => < switch(action.type) < case ADD_POST: < let newPost = < id: 5, message: action.newPostText, likesCount: 0 >; return < . state, posts: [. state.posts, newPost] >; > default: return state; > > export const addPostActionCreator = (newPostText) => (); export default profileReducer;

Как сделать валидацию?

Валидация может вешаться на поля (Field-Level Validation), чтобы сразу после потери фокуса показывать предупреждение, а может на отправку формы (Submit Validation) и показвать предупреждения после нажатия на кнопку. Также она может быть ассинхронной, т.е. во время ввода идет проверка на сервере (Async Validation).

Мы рассмотрим, наверное, самую удобную для пользователя разновидность – Field-Level Validation, т. е. на поля.

    Создаем файл src/utils/validators/validators.js Валидатор – это функция, которая получит value и ее можно прицепить к форме. Вот такие валидаторы мы и создадим в этом файле:

export const required = value => < if (value) return undefined; return 'Field is required'; >export const maxLengthCreator = (maxLength) => (value) => < if (value.length >maxLength) return `Max length is $ sybols`; return undefined; >
const maxLength10 = maxLengthCreator(10); const AddPostForm = (props) => < return ( 
>
name="newPostBody" placeholder="Post message" validate= <[required, maxLength10]>/>
) >
import React from 'react'; export const Textarea = () => < //деструктуризируем в скобках пропсы return ( 
/>
) > export const Input = () => < //деструктуризируем в скобках пропсы return (
/>
) >
 name="newPostBody" placeholder="Post message" validate= <[required, maxLength10]>/>
import React from 'react'; import styles from './FormsControls.module.css'; export const Textarea = () => < const hasError = meta.touched && meta.error; //условие ошибки кладем в переменную для удобства return ( 
>
/>
> // в meta.error приходит текст ошибки
) >
import React from 'react'; import styles from './FormsControls.module.css'; const FormControl = () => < const hasError = meta.touched && meta.error; return ( 
>
>
) > export const Textarea = (props) => < const = props; return > /> > export const Input = (props) => < const = props; return > /> >

Обработка форм в React с помощью хуков

В этой статье рассмотрим, как обрабатывать формы в приложениях react с помощью хуков.

Формы

Формы позволяют нам принимать данные от пользователей и отправлять их на сервер для обработки. Это различные типы форм, такие как «Вход», «Регистрация» и т.д. В HTML5 есть элементы формы, такие как input , textarea , select , они поддерживают собственное внутреннее состояние в DOM, но в React мы поддерживаем состояние элементов формы внутри компонента, чтобы мы могли иметь полный контроль над элементами формы.

Что такое обработка форм

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

import React, from 'react'; function Form() < const [name,setName] = useState(''); function handleNameChange(e)< setName(e.target.value) >function handleSubmit(e) < e.preventDefault() // останавливаем перезагрузку страницы по умолчанию console.log(name); >return ( 
> onChange=/>
) >

В приведенном выше коде мы установили для атрибута value элемента input свойство name , а метод обработчика событий onChange - handleNameChange - запускается каждый раз, когда мы вводим некоторые данные в элемент input , и он обновляет свойство name с помощью метода setName , так что мы продолжаем синхронизировать значение с состоянием react. handleSubmit используется для отправки формы.

Элемент select

import React, from 'react'; function FormSelect() < // начальное значение состояния - строка 'react' const [framework, setFramework] = useState('react'); function handleChange(e)< setFramework(e.target.value); >; function handleSubmit(e)< e.preventDefault(); console.log(framework); >; return ( 
>

Choose your framework

); >

Здесь мы создали выпадающий список фреймворков в элементе мы установили атрибут value для свойства framework и добавили обработчик событий onChange . Вложенные элементы содержат атрибут value , который содержит данные, так что всякий раз, когда мы выбираем конкретный параметр, вызывается метод handleChange и изменяет значение свойства framework значением атрибута . Вы видели, что элемент select также следует аналогичному шаблону, как и элемент input , так почему бы нам не создать пользовательский хук и повторно использовать его в каждом элементе формы?

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

import React, from 'react'; function useInput(initialValue) < const [value,setValue] = useState(initialValue); function handleChange(e) < setValue(e.target.value); >return [value,handleChange]; >

Здесь мы создали пользовательский хук под названием useInput , давайте его применим.

Использование пользовательского хука useInput()

function LoginForm() < const [email, setEmail] = useInput(''); const [password, setPassword] = useInput(''); function handleSubmit(e)< e.preventDefault(); console.log(email,password) >return ( 
> onChange=/> onChange=/>
) >

Теперь наш компонент LoginForm выглядит намного чище с помощью пользовательского хука useInput() . Точно так же мы можем использовать наш хук useInput с другими элементами формы.

Пример с Radio button

function RadioButtons() < const [data] = useState() const [gender, setGender] = useInput(""); function handleSubmit(e) < e.preventDefault(); console.log(gender); >return ( 
>

Select Your Gender

checked= onChange=/>
checked= onChange=/>
checked= onChange=/>
) >

Пример элемента Textarea

function Comments() < const [comment, setComment] = useInput(""); function handleSubmit(e) < e.preventDefault(); console.log(comment); >return( 
> onChange=/>
) >

Где должна быть бизнес-логика в React приложении

5 месяцев назад · 6 мин. на чтение

В этой статье мы подробно рассмотрим работу с бизнес-логикой в React

  • Структура React приложения
  • Архитектура современного React приложения

Как обстоят дела в React

Рассмотрим проблему на более высоком уровне. Если вы внимательно посмотрите на React и согласитесь, что он отвечает только за визуальную часть нашего приложения, многие проблемы будут решены автоматически. Независимо от того, используем ли мы традиционные шаблоны MVC/MVP или их вариант MVVM, если React — это V, очевидно, нам нужно что-то еще, чтобы заполнить роль M или VM в приложении. Среди многих проектов я также обнаружил, что многие хорошие практики, которые мы используем в бэкенде, не признаны в мире фронтенда, такие как слоеная структура, паттерны проектирования и т. д. Одна из возможных причин заключается в том, что фронтенд относительно молодой и ему нужно некоторое время, чтобы наверстать упущенное. Например, в типичном приложении Spring MVC у нас были бы controller , service и repository , и каждый разработчик принимает причину такого разделения: controller не содержит бизнес-логики, service не знает, как модель отображается или сериализуется для пользователей, а repository работает только о доступом к данным. Однако во фронтенд-приложениях на React из-за отсутствия встроенной поддержки (например, отсутствия контроллеров или слоя репозитория) мы вместо этого пишем этот код в компоненты. И это приведет к тому, что бизнес-логика будет повсюду. Итерации станут медленными, а качество кода низким.

Утечка бизнес-логики

  • Использование преобразователей данных
  • x.y.z
  • Защитное программирование

Использование преобразователей данных

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

fetch(`https://example.com/api/addresses`) .then((r) => r.json()) .then((data) => < const addresses = data.map((item: RemoteAddress) =>(< street: item.streetName, address: item.streetAddress, postcode: item.postCode >)) setAddresses(addresses) >);
  • Компонент должен знать тип RemoteAddress
  • Компоненту необходимо определить новый тип Address ( setAddresses )
  • data.map выполняет низкоуровневое сопоставление

Симптом x.y.z (нарушение закона Деметры)

Если вы используете более одного оператора точки . , вероятно, это означает, что отсутствуют некоторые концепции. person.deliveryAddress лучше, чем person.primaryAddress.street.streetNumber + person.primaryAddress.suburb так как первый вариант правильно скрывает детали. Приведенный ниже код показывает, что ProductDialog слишком много знает о product , и как только структура product изменится, нам придется менять множество мест (тесты и компоненты)

const ProductDialog = (props) => < const < product >= props; if(product.item.type === 'Portion') < //do something >>

Здесь мы имеем дело с данными, а не с моделью. Таким образом, product.isPortion() будет более значимым, чем проверка необработанных данных.

Защитное программирование

Во многих проектах люди склонны делать слишком много в компоненте, и это создает много шума в коде. Например:

const ProductDetails = (props) => < const < product >= props const < item >= product const < media >= item as MenuItem const title = (media && media.name) || '' const description = (media && media.description) || '' return ( 
) >

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

Как решить проблему?

  1. Регулярный рефакторинг
  2. Создание моделей

Регулярный рефакторинг

  • Использования преобразователей данных
  • x.y.z
  • Защитного программирования
const transformAddress: Address = (address: RemoteAddress) => < return (< street: datum.streetName, address: datum.streetAddress, postcode: datum.postCode >) > //. const addresses = data.map(transformAddress)

Также иногда бывает нужно преобразовать аббревиатуры в текст такие как VIC или NSW, но нам нужно показать их в полном тексте на странице как Victoria или New South Wales.

const states = < vic: "Victoria", nsw: "New South Wales", //. >; const transformAddress: Address = (address: RemoteAddress) => < return < street: address.streetName, address: address.streetAddress, postcode: address.postCode, state: states[address.state.toLowerCase()] >; >;

Точно так же мы можем использовать функцию, для проверки title и description и вывода запасного значения:

const getTitle = (media) => (media && media.name) || '' const getDescription = (media) => (media && media.description) || ''

По мере добавления все больше и больше логики, такой transformAddress и getTitle , они будут перемещаться в helpers.ts , в конечном итоге у нас будет огромный файл. Это означает, что он станет нечитаемым и будет иметь высокие затраты на обслуживание. Мы можем разделить файл на модули, но связи между этими функциями могут затруднить их понимание. Это похоже на проблему, с которой мы сталкивались до объектно-ориентированного программирования - у нас слишком много модулей и функций в каждом модуле, и слишком сложно ориентироваться в них. Другими словами, нам нужен лучший способ организации этих вспомогательных функций. К счастью, нам не нужно изобретать велосипеды. Нам может помочь объектно-ориентированное программирование. Просто используя классы и инкапсуляцию в ООП, мы можем легко сгруппировать эти функции и сделать код намного более читабельным. Чтобы сгруппировать код создадим модели.

Создание моделей

Короче говоря, создание моделей — это объединение данных и поведения, сокрытие деталей и обеспечение общего API для потребителей. Например, мы не должны использовать product.item.type === 'Portion' , вместо этого мы должны создать класс Product , и у него есть isPortion для их потребителей. Это очень распространено в бэкенд-сервисах, но не получило широкого распространения в мире фронтенда. Причина в том, что, как упоминалось выше, люди упускают из виду, что React отвечает только за визуализацию. И здоровое фронтенд-приложение должно иметь и другие части. Ему нужны модели и логика для взаимодействия с серверной частью, даже для ведения логирования. Возвращаясь к приведенному выше примеру, определив класс Address для замены анонимной функции внутри data.map , мы получим:

class Address < constructor(private addr: RemoteAddress) <>get street() < return this.addr.streetAddress; >get postcode() < return this.addr.postcode; >>

Нет никакой разницы в использовании:

Единственное, что нужно изменить, это заменить transformAddress на new Address :

const addresses = data.map((addr: RemoteAddress) => new Address(addr))

И для частного члена/функции для перевода названия штата:

private readonly states = < vic: "Victoria", nsw: "New South Wales", //. >; get state()

Структура теперь намного точнее. states теперь является приватным членом класса Address . Класс хорош тем, что он объединяет всю связанную логику в одну часть, что делает его изолированным и простым в обслуживании. Размещение всей связанной логики в одном месте имеет и другие преимущества. Во-первых, такое разделение делает тестирование простым и надежным, поскольку компоненты зависят от модели (а не от исходных данных). Нам не нужно готовить данные с нулевым значением или значения вне границ предусмотренных значений для тестов компонентов. Точно так же модель тестирования больше фокусируется на данных и логике (пустое значение, проверка и запасное значение). Во-вторых, согласованность повышает вероятность его повторного использования в других сценариях. Наконец, если нам нужно переключиться на другую стороннюю службу, нам нужно только изменить модели, и представления могут остаться нетронутыми. По мере того, как создается все больше и больше моделей, нам может понадобиться целый слой для них. Эта часть кода не знает о существовании компонентов пользовательского интерфейса и связана исключительно с бизнес-логикой.

Итоги

Инкапсуляция бизнес-логики, даже в контексте тонких клиентов, является относительно большой темой. В этой статье мы рассмотрели несколько симптомов утечки бизнес-логики и то, как с ними бороться. Проводя регулярный рефакторинг, мы можем гарантировать, что компоненты отвечают только за рендеринг данных и не должны выполнять какие-либо вычисления или сопоставление данных. Мы должны разделить эту логику на чистые файлы JavaScript (а не jsx/tsx). И с помощью создания моделей мы можем использовать объекты только для того, чтобы скрыть детали доступа к данным. Преимущества этого подхода заключаются в том, что тестирование как модели, так и представлений значительно упрощается, легче отслеживать изменения бизнес-требований и гораздо более простой код в представлениях (поскольку большая часть этого делается в моделях).

Использование Axios с React

Использование Axios с React

Многим веб-проектам на некотором этапе их развития требуется взаимодействие с REST API. Axios — это облегченный клиент HTTP на базе сервиса $http с Angular.js v1.x, похожего на собственный JavaScript Fetch API.

Axios основан на промисах, что дает вам возможность использовать возможности JavaScript async и await для получения более удобочитаемого асинхронного кода.

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

В этой статье вы увидите примеры использования Axios для доступа к популярному JSON Placeholder API из приложения React.

Предварительные требования

Чтобы следовать за примерами этой статьи, вам потребуется следующее:

  • Node.js версии 10.16.0, установленный на вашем компьютере. Чтобы установить его в macOS или Ubuntu 18.04, следуйте указаниям руководства Установка Node.js и создание локальной среды разработки в macOS или раздела Установка с помощью PPA руководства Установка Node.js в Ubuntu 18.04.
  • Новый проект React, настроенный с помощью приложения Create React App в соответствии с указаниями учебного модуля Настройка проекта React с помощью приложения Create React App.
  • Также вам нужно понимать основы языка JavaScript, для изучения которого вам подойдет серия Программирование на JavaScript, а также обладать базовыми знаниями языков HTML и CSS.

Шаг 1 — Добавление Axios в проект

В этом разделе мы добавим Axios в проект React digital-ocean-tutorial , созданный вами при выполнении учебного модуля Настройка проекта React Project с помощью приложения Create React App.

Чтобы добавить Axios в проект, откройте терминал и поменяйте каталоги в вашем проекте:

Затем запустите эту команду для установки Axios:

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

Шаг 2 — Создание запроса GET

В этом примере мы создадим новый компонент и импортируем в него Axios для отправки запроса GET .

Создайте в папке src вашего проекта React новый компонент с именем PersonList.js :

Добавьте в компонент следующий код:

digital-ocean-tutorial/src/PersonList.js

import React from 'react'; import axios from 'axios'; export default class PersonList extends React.Component  state =  persons: [] > componentDidMount()  axios.get(`https://jsonplaceholder.typicode.com/users`) .then(res =>  const persons = res.data; this.setState( persons >); >) > render()  return ( ul>  this.state.persons.map(person => li>person.name>/li>)> /ul> ) > > 

Вначале вы импортируете React и Axios так, чтобы их можно было использовать в компоненте. Затем вы прикрепляетесь к крюку жизненного цикла componentDidMount и выполняете запрос GET .

Вы используете axios.get(url) с URL от конечной точки API, чтобы получить промис, возвращающий объект ответа. Внутри объекта ответа имеются данные, которым присвоено значение person .

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

Шаг 3 — Составление запроса POST

На этом шаге мы используем Axios с еще одним методом запросов HTTP, а именно POST .

Удалите предыдущий код в PersonList и добавьте следующий код, чтобы создать форму для ввода данных пользователя и последующей отправки контента в API методом POST :

digital-ocean-tutorial/src/PersonList.js

 import React from 'react'; import axios from 'axios'; export default class PersonList extends React.Component  state =  name: '', > handleChange = event =>  this.setState( name: event.target.value >); > handleSubmit = event =>  event.preventDefault(); const user =  name: this.state.name >; axios.post(`https://jsonplaceholder.typicode.com/users`,  user >) .then(res =>  console.log(res); console.log(res.data); >) > render()  return ( div> form onSubmit=this.handleSubmit>> label> Person Name: input type="text" name="name" onChange=this.handleChange> /> /label> button type="submit">Add/button> /form> /div> ) > > 

Внутри функции handleSubmit вы предотвратили действие формы по умолчанию. Затем следует обновить state на ввод user .

Использование POST дает тот же объект ответа с информацией, которую вы сможете использовать внутри вызова then .

Чтобы выполнить запрос POST , мы вначале захватываем ввод user . Затем мы добавляем ввод вместе с запросом POST и получаем ответ. Вы можете отправить ответ в console.log , где ввод user будет показан в форме.

Шаг 4 — Создание запроса DELETE

В этом примере вы видите, как удалять элементы из API, используя axios.delete и передавая URL как параметр.

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

digital-ocean-tutorial/src/PersonList.js

 import React from 'react'; import axios from 'axios'; export default class PersonList extends React.Component  state =  id: '', > handleChange = event =>  this.setState( id: event.target.value >); > handleSubmit = event =>  event.preventDefault(); axios.delete(`https://jsonplaceholder.typicode.com/users/$this.state.id>`) .then(res =>  console.log(res); console.log(res.data); >) > render()  return ( div> form onSubmit=this.handleSubmit>> label> Person ID: input type="text" name="id" onChange=this.handleChange> /> /label> button type="submit">Delete/button> /form> /div> ) > > 

В этом случае объект res предоставляет информацию о запросе. Затем вы можете снова использовать console.log для этой информации после отправки формы.

Шаг 5 — Использование базового экземпляра в Axios

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

Создайте отдельный файл с именем api.js :

Экспортируйте новый экземпляр axios со следующими значениями по умолчанию:

digital-ocean-tutorial/src/api.js

import axios from 'axios'; export default axios.create( baseURL: `http://jsonplaceholder.typicode.com/` >); 

После настройки экземпляра по умолчанию его можно использовать внутри компонента PersonList . Новый экземпляр импортируется следующим образом:

digital-ocean-tutorial/src/PersonList.js

import React from 'react'; import axios from 'axios'; import API from '../api'; export default class PersonList extends React.Component  handleSubmit = event =>  event.preventDefault(); API.delete(`users/$this.state.id>`) .then(res =>  console.log(res); console.log(res.data); >) > > 

Поскольку http://jsonplaceholder.typicode.com/ теперь является базовым URL, вам больше не потребуется вводить URL полностью каждый раз, когда вы захотите использовать другую конечную точку API.

Шаг 6 — Использование async и await

В этом примере вы видите, как использовать async и await для работы с промисами.

Ключевое слово await разрешает промис и возвращает значение . Затем значение может быть присвоено переменной.

handleSubmit = async event =>  event.preventDefault(); // const response = await API.delete(`users/$this.state.id>`); console.log(response); console.log(response.data); >; 

В этом примере кода выполняется замена .then() . Промис разрешается, и его значение сохраняется в переменной response .

Заключение

В этом учебном модуле мы изучили несколько примеров использования Axios в приложении React для создания запросов HTTP и ответов обработки.

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

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Формы

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

form> label> Имя: input type="text" name="name" /> label> input type="submit" value="Отправить" /> form>

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

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

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

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

class NameForm extends React.Component  constructor(props)  super(props); this.state = value: ''>; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); > handleChange(event)  this.setState(value: event.target.value>); > handleSubmit(event)  alert('Отправленное имя: ' + this.state.value); event.preventDefault(); > render()  return ( form onSubmit=this.handleSubmit>>  label> Имя: input type="text" value=this.state.value> onChange=this.handleChange> />  label> input type="submit" value="Отправить" /> form> ); > >

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

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

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

textarea> Привет! Тут просто немного текста внутри тега textarea textarea>

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

class EssayForm extends React.Component  constructor(props)  super(props); this.state =  value: 'Будьте любезны, напишите сочинение о вашем любимом DOM-элементе.' >; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); > handleChange(event)  this.setState(value: event.target.value>); > handleSubmit(event)  alert('Сочинение отправлено: ' + this.state.value); event.preventDefault(); > render()  return ( form onSubmit=this.handleSubmit>> label> Сочинение: textarea value=this.state.value> onChange=this.handleChange> />  label> input type="submit" value="Отправить" /> form> ); > >

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

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

select> option value="grapefruit">Грейпфрутoption> option value="lime">Лаймoption> option selected value="coconut">Кокосoption> option value="mango">Мангоoption> select>

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

class FlavorForm extends React.Component  constructor(props)  super(props); this.state = value: 'coconut'>; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); > handleChange(event)  this.setState(value: event.target.value>); > handleSubmit(event)  alert('Ваш любимый вкус: ' + this.state.value); event.preventDefault(); > render()  return ( form onSubmit=this.handleSubmit>> label> Выберите ваш любимый вкус: select value=this.state.value> onChange=this.handleChange>>  option value="grapefruit">Грейпфрутoption> option value="lime">Лаймoption> option value="coconut">Кокосoption> option value="mango">Мангоoption> select> label> input type="submit" value="Отправить" /> form> ); > >

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

Примечание

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

select multiple=true> value=['Б', 'В']>>

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

input type="file" />

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

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

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

class Reservation extends React.Component  constructor(props)  super(props); this.state =  isGoing: true, numberOfGuests: 2 >; this.handleInputChange = this.handleInputChange.bind(this); > handleInputChange(event)  const target = event.target; const value = target.type === 'checkbox' ? target.checked : target.value; const name = target.name; this.setState(  [name]: value >); > render()  return ( form> label> Пойдут: input name="isGoing" type="checkbox" checked=this.state.isGoing> onChange=this.handleInputChange> /> label> br /> label> Количество гостей: input name="numberOfGuests" type="number" value=this.state.numberOfGuests> onChange=this.handleInputChange> /> label> form> ); > >

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

this.setState(  [name]: value>);
var partialState = >; partialState[name] = value;this.setState(partialState);

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

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

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

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

ReactDOM.createRoot(mountNode).render(input value="Привет" />); setTimeout(function()  ReactDOM.createRoot(mountNode).render(input value=null> />); >, 1000);

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

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

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *