Pull to refresh

Контролируемые и неконтролируемые компоненты в React не должны быть сложными

Reading time4 min
Views36K
Привет, Хабр! Представляю вашему вниманию перевод статьи «Controlled and uncontrolled form inputs in React don't have to be complicated» автора Gosha Arinich.

Возможно, вы видели много статей, говорящих: “вы не должны использовать “setState”", в то время, когда документы утверждают, что “refs — это плохо”. Всё это очень противоречиво. Иногда, трудно понять, как сделать все правильно, а так же каковы критерии выбора между этими методами.

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

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

Неуправляемые компоненты


Неуправляемые компоненты похожи на обычные HTML-формы:

class Form extends Component {
  render() {
    return (
      <div>
        <input type="text" />
      </div>
    );
  }
}

Они запоминают всё, что вы печатали. Затем вы можете получить их значение, используя ref. Например, в обработчике onClick:


class Form extends Component {
  handleSubmitClick = () => {
    const name = this._name.value;
    // do something with `name`
  }
  render() {
    return (
      <div>
        <input type="text" ref={input => this._name = input} />
        <button onClick={this.handleSubmitClick}>Sign up</button>
      </div>
    );
  }
}

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

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

Управляемые компоненты:


Управляемый компонент принимает свое текущее значение в качестве пропсов, а также коллбэк для изменения этого значения. Вы можете сказать, что это более “реактивный” способ управления компонентом, однако это не означает, что вы всегда должны использовать этот метод.

<input value={someValue} onChange={handleChange} />

Это все очень хорошо, но значение формы ввода должно существовать в неком state. Как правило, компонент, который рэндерит форму ввода (т.е. форма), сохраняет их в своем state:


class Form extends Component {
  constructor() {
    super();
    this.state = {
      name: '',
    };
  }

  handleNameChange = (event) => {
    this.setState({ name: event.target.value });
  };

  render() {
    return (
      <div>
        <input
          type="text"
          value={this.state.name}
          onChange={this.handleNameChange}
        />
      </div>
    );
  }
}

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

Каждый раз, когда вы вводите новый символ, вызывается handleNameChange. Он принимает новое значение формы ввода и записывает его в state.

image

  • Все начниается с пустой строки — ‘’;
  • Вы вводите букву ‘a’, и handleNameChange получает её и вызывает setState. Затем форма ввода заново рендерится со значением ‘a’;
  • Вы вводите букву ‘b’, и handleNameChange получает значение ‘ab’ и устанавливает его в state. Форма ввода опеть рендерится, но теперь со значением ‘ab’.

Этот поток словно «заталкивает» изменения в форму, именно поэтому компонент всегда имеет текущее значение входных данных, не требуя явного запроса на обновление.

Это означает, что ваши данные (state) и пользовательский интерфейс (форма ввода) всегда синхронизированы. State дает значение форме, в то время как форма изменяет текущее значение state.

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

  • быстрой обратной связи, например валидации;
  • отключения определенной кнопки, до тех пор пока все поля формы не будут валидны;
  • обеспечения обработки определенных форматов полей ввода, например номеров кредитных карт.

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

Что делает компонент “управляемым”?


Конечно, есть и другие элементы формы, такие как: checkboxes, radio, textarea и select.
Компонент становится управляемым, когда вы устанавливаете его значение используй props. Вот и всё.

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

Элемент Значение Коллбэк для изменения Новое значение в коллбэке
<input type="text" />
value=«string» onChange event.target.value
<input type="checkbox" />
checked={boolean} onChange event.target.checked
<input type="radio" />
checked={boolean} onChange event.target.checked
<textarea />
value=«string» onChange event.target.value
<select />
value=«option value» onChange event.target.value

Выводы


Как управляемые, так и неуправляемые компоненты имеют свои достоинства и недостатки. Оцените конкретную ситуацию и выберите подход — если для вас это работает, то почему бы не воспользоваться этим?

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

image

Кроме того, выбор типа компонента — это не то решение, которое принимается раз и навсегда: вы всегда можете заменить неуправляемые компоненты на управляемые. Переход от одного к другому не так уж и сложен.
Tags:
Hubs:
Total votes 7: ↑7 and ↓0+7
Comments11

Articles