Работа с input
ОБНОВЛЕНИЕ 2018: в учебнике хорошая теория, но ему уже два года. Проверяйте версии пакетов. За выходом нового учебника можно следить в telegram канале или twitter
На канале так же проводятся бесплатные вебинары, публикуются переводы и авторские материалы, присоединяйтесь!
Работа с input
Сперва приберемся:
Удалим лишние console.log'и, удалим обработчик onTotalNewsClick.
Затем создадим компонент - <TestInput />
, который будет просто отрисовывать (render) - input перед списком новостей.
Полный листинг нашего кода после данных манипуляций:
js/app.js
Напомню про комментарии:
Первый комментарий, добавлен с помощью //
, так как данный комментарий не находится внутри JSX. А второй - находится, следовательно имеет вид {/* комментарий */}
.
Вообще, код сейчас не работает (но это не из-за комментария). Давайте посмотрим на ошибку внимательно:
Вы предоставили свойство value для поля, у которого нет onChange обработчика. Поэтому отрисовано поле только для чтения. Если поле должно быть изменяемо, используйте defaultValue. Либо установите onChange или readOnly. Проверьте render метод компонента TestInput.
Не могу не любить react за такие подробные сообщения об ошибках.
А вы кстати попробуйте сейчас изменить значение инпута. Ничего не выйдет. Здесь у нас есть два пути, и первый нам известный - использовать какое-нибудь свойство state в качестве динамически изменяемого значения инпута.
Controlled components (контролируемые компоненты)
Для вызова setState, будем использовать событие onChange. Работа с ним не отличается от работы с onClick или другими любыми событиями. Главное - передать функцию-обработчик.
Не торопитесь, давайте подумаем еще раз:
Нам нужно передать функцию обработчик, которая будет изменять какую-то переменную состояния.
Значит нам нужно создать начальное состояние (getInitialState).
Если у нас есть переменная состояния компонента, значит мы хотим, чтобы именно она была в качестве value у нашего инпута.
Сможете сделать сами? Если да - отлично, если нет - решение ниже.
Подсказка #1: так может выглядеть функция-обработчик
Решение:
У нас есть placeholder - "введите значение", который будет показываться в момент загрузки страницы, так как наше начальное состояние input'a - пустая строка. При изменении, мы устанавливаем в переменную myValue - то что введено в input. Следовательно - input корректно изменяется.
Обычно, мы хотим по клику отправлять значения инпута...
Задача: По клику на кнопку - показывать alert с текстом инпута.
Попробуйте сами.
Подсказка #1:
Вам необходимо сделать: добавить кнопку, на кнопку "повесить" обработчик onClick, в функции обработчике считывать значение this.state.myValue
.
Подсказка #2:
Так как нам необходимо рендерить больше одного элемента, нужно обернуть их в родительский элемент, например в <div></div>
Решение:
Предлагаю добавить отступы для .test-input:
css/app.css
После добавления отступа в данном коде ничего не раздражает. Или нет? Как думаете, что здесь может расстроить борца за оптимизацию?
Ответ: каждый раз, после любого изменения у нас вызывается setState, а значит - полная перерисовка компонента. Не очень приятно. Опять же, чуть больше логики в момент создания компонента и в пору будет расстроиться от "отзывчивого" поля ввода.
Поэтому, наш выбор - это второй путь. Неконтролируемый компонент!
Uncontrolled Components (неконтролируемый компонент)
Главное отличие неконтролируемого компонента от контролируемого в том, что у него нет обработчика изменений, а значит нет постоянных вызовов setState и перерисовок.
Для того чтобы считать значение такого компонента используется вспомогательная функция вспомогательной библиотеки ReactDOM - ReactDOM.findDOMNode, а для того, чтобы можно было найти с помощью нее элемент, используется атрибут ref.
Для неконтролируемого компонента требуется указывать defaultValue.
Начнем по порядку:
Удалим обработчик onChange
Удалим getInitialState
Укажем defaultValue = пустая строка (
defaultValue=''
) вместо valueДобавим атрибут ref, назовем его myTestInput
Обновите страницу, попробуйте ввести значение. Работает? Работает!
Теперь нам нужно, научиться считывать значение: перепишите onBtnClickHandler следующим образом:
Метод ReactDOM.findDomNode принимает ссылку (this.refs.МОЙ_ЭЛЕМЕНТ
) и возвращает нативный DOM элемент. Для тех кто в танке: $('.my-input')
- возвращает jQuery обертку над элементом. У jQuery обертки обычно больше методов и свойств.
Напоследок, давайте поконсолим значения, посмотрим что к чему.
Добавьте атрибут ref для кнопки рядом с инпутом. А затем в обработчике onBtnClickHandler сконсольте this.refs
В браузере:
Как видите, this.refs содержит все refs компонента. Если попробовать раскрыть свойства какого-нибудь из них - реакт ругнется. Общий посыл: не нужно лезть в DOM. Он прав, обычно такой необходимости нет. А для нашего случая как раз и созданы refs.
В качестве "итого" на этот раз, вам необходимо прочитать первые 3 абзаца из раздела Uncontrolled Components. Сейчас, все должно быть понятно!
За этот урок, мы научились с вами не вызывать дорогой setState и render на "каждый чих".
P.S. конечно, в данном случае никакого выигрыша в производительности нет. Оба подхода хорошо сработают.
Вариант с контролируемыми и неконтролируемыми компонентами, работа с defaultValue и state являются одинаковыми для всех элементов форм.
Очень рекомендую посмотреть страницу документации на англ.языке по элементам форм
Исходный код на данный момент (включая alert и console.log).
Last updated