3.4 Неконтролируемые компоненты

В большинстве случаев мы рекомендуем использовать контролируемые компоненты при реализации форм. В контролируемом компоненте данные формы обрабатываются компонентом React. Альтернативу представляют неконтролируемые компоненты, где данные формы обрабатываются самим DOM.

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

К примеру, данный код принимает только имя пользователя в неконтролируемом компоненте:


Код
    
  class SearchUserForm extends React.Component {
    constructor(props) {
      super(props);
      this.onSubmit = this.onSubmit.bind(this);
    }

    onSubmit(event) {
      alert(`Имя пользователя: ${this.nameTextField.value}`);
      event.preventDefault();
    }

    render() {
      return (
        <form onSubmit={this.onSubmit}>
          <label>Имя пользователя:
      <input ref={(el) => this.nameTextField = el} name="name" type="text"/></label>
          <input type="submit" value="Submit" />
        </form>
      );
    }
  }

  ReactDOM.render(<SearchUserForm />,  document.getElementById('root'));
  

Посмотреть в CodePen


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

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


В жизненном цикле отрисовки React атрибут value на элементах формы будет переопределять значение в DOM. Используя неконтролируемые компоненты, нам часто может понадобиться, чтобы React определил начальное значение, избежав последующих неконтролируемых обновлений. Чтобы обработать этот случай, вы можете указать атрибут defaultValue, вместо атрибута value:


Код
    
  render() {
    return (
      <form onSubmit={this.onSubmit}>
        <label>Имя пользователя:
          <input defaultValue="Вася"
            ref={(el) => this.nameTextField = el} name="name" type="text"/></label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
  

Аналогично, <input type="checkbox"> и <input type="radio"> поддерживают defaultChecked, а <select> и <textarea> поддерживают defaultValue.


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


Код
    
  <input type="file" />
  

Это неконтролируемый компонент в React, так как его значение может быть установлено только пользователем, но не программно.

Вы должны использовать File API для взаимодействия с файлами. В следующем примере показано, как создать ссылку на узел DOM для доступа к файлу(ам) в submit-обработчике:


Код
    
  class FileInput extends React.Component {
    constructor(props) {
      super(props);
      this.handleSubmit = this.handleSubmit.bind(this);
    }
    handleSubmit(event) {
      event.preventDefault();
      alert(`Selected file - ${this.fileInput.files[0].name}`);
    }
  
    render() {
      return (
        <form onSubmit={this.handleSubmit}>
          <label>
            Upload file:
            <input
                    type="file"
                    ref={input => {
                this.fileInput = input;
              }}
            />
          </label>
          <br />
          <button type="submit">Submit</button>
        </form>
      );
    }
  }
  
  ReactDOM.render(
    <FileInput />,
    document.getElementById('root')
  );
  

Посмотреть в CodePen