Работа с формой

ОБНОВЛЕНИЕ 2018: в учебнике хорошая теория, но ему уже два года. Проверяйте версии пакетов. За выходом нового учебника можно следить в telegram канале или twitter

На канале так же проводятся бесплатные вебинары, публикуются переводы и авторские материалы, присоединяйтесь!

Работа с формой

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

Результатом добавления новости, пока что, вновь, будет alert с текстом новости.

Переименуйте <TestInput /> в <Add />, и рендерите в нем следующую форму: автор (input), текст новости (textarea), "я согласен с правилами" (checkbox), "показать alert" (button).

Попутно изменим названия классов, удалим лишние обработчики и переместим компонент <Add /> перед заголовком "Новости".

var Add = React.createClass({
  componentDidMount: function() {
    ReactDOM.findDOMNode(this.refs.author).focus();
  },
  onBtnClickHandler: function(e) {
    e.preventDefault();
  },
  render: function() {
    return (
      <form className='add cf'>
        <input
          type='text'
          className='add__author'
          defaultValue=''
          placeholder='Ваше имя'
          ref='author'
        />
        <textarea
          className='add__text'
          defaultValue=''
          placeholder='Текст новости'
          ref='text'
        ></textarea>
        <label className='add__checkrule'>
          <input type='checkbox' defaultChecked={false} ref='checkrule' />Я согласен с правилами
        </label>
        <button
          className='add__btn'
          onClick={this.onBtnClickHandler}
          ref='alert_button'>
          Показать alert
        </button>
      </form>
    );
  }
});

Если вы не против моего оформления, можете взять стили для компонента <Add />:

Отключим кнопку "показать alert", если не отмечен чекбокс. Здесь есть 2 варианта - использовать state или не использовать. Для нашей задачи никаких проблем с производительностью не будет, если мы будем использовать state. Так даже лучше, чем "лезть в DOM". Но я все же приведу оба решения на всякий случай.

Решение 1: без использования state.

Добавьте инпуту обработчик onChange, и добавьте функцию обработчик.

Проверьте в браузере. При первой загрузке, кнопка активна, хотя чекбокс не стоит. Хех, решается на HTML ;) Добавьте атрибут disabled кнопке.

Решение 2: с использованием state

  • добавьте getInitialState компоненту <Add />;

  • удалите defaultChecked из инпута;

  • сделайте атрибут disabled у кнопки равным значению из state;

  • измените функцию обработчик;

Приведу полный код компонента <Add />

checkbox state screen

Какое решение выбрать?

В данном случае я за второй вариант. Для меня большим злом является необходимость работать с DOM, чем "рендер" компонента <Add /> на каждый клик по чекбоксу. В данный момент я могу гарантировать, что никакой проблемы с производительностью не будет. Но заметьте, для input'a я все же оставил по прежнему схему работы через DOM. Путано? Я руководствовался тем, что клик по чекбоксу - событие не частое, а возможно единичное. <input /> и <textarea></textarea> - более вредные в моем понимании. События onChange происходят в них слишком часто.

Работайте как вам нравится, просто знайте, что есть два варианта.

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

Решение:

Достаточно всего лишь подкорректировать функцию onBtnClickHandler

Блокировка кнопки, если не все поля заполнены

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

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

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

Попробуйте сами, а потом сверьтесь с решением.

Задача: если в поле "автор" или "текст" не введено ничего (либо пробелы) - кнопка "показать alert" должна быть недоступной.

Подсказка #1: для удаления пробелов используйте стандартный метод trim()

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

Подсказка #3: объявите обработчики на onChange

Если вас смущает дублирование кода - спокойствие, позже порефакторим.

Подсказка #4: у атрибута disabled проверяйте выполнение условия: если хотя бы одно из свойств состояния (agreeNotChecked, authorIsEmpty, textIsEmpty) имеет значение true - кнопка выключается.

Решение: код компонента <Add /> полностью:

Избавляемся от дублирования кода

Дублирование кода в функциях onAuthorChange и onTextChange - это плохо. Хорошо было бы создать одну функцию, которая принимала бы аргумент - fieldName и изменяла бы соответствующую переменную в state согласно нашей логике.

Как передать аргумент в функцию? Что насчет такого варианта:

Откровенно плохой вариант. Функция сразу же выполнится - так как указаны ().

Нам нужно передать именно функцию, а не результат ее выполнения. На помощь приходит метод bind().

Верной строкой для onChange в таком случае будет:

Для input'a:

Для textarea:

Напишем саму функцию onFieldChange:

Я надеюсь, не возникает вопросов, откуда взялся аргумент fieldName, почему аргумент 'e' теперь второй? (если что, это все bind виноват, он "прокинул" нашу переменную в функцию первым аргументом, можно было прокинуть еще...)

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

Возможно вам покажется более читаемым такой вариант:

Разницы между ними нет, в этом "противостоянии" я выбираю первый вариант.

Итого: мы разобрали пару стандартных способов блокировать нажатие кнопки на форме. Мы опять не взяли событие onSubmit для формы и ограничились лишь событием onClick.

По традиции - исходный код на данный момент.

Last updated

Was this helpful?