Pull to refresh

Ref-атрибуты и DOM в React

Reading time4 min
Views88K
Original author: @lacker, @gaearon, @arnif

React. Продвинутые руководства. Часть Третья


Продолжение серии переводов раздела "Продвинутые руководства" (Advanced Guides) официальной документации библиотеки React.js.


Ref-атрибуты и DOM в React


В типовом потоке данных React, свойства (props) — это единственный способ, с помощью которого родители взаимодействуют со своими потомками. Для модификации потомка, вам необходимо заново отобразить (произвести ререндеринг) его с новыми свойствами. Однако, в некоторых случаях, вам понадобится модифицировать потомка непосредственно, вне основного потока. Изменение потомка возможно в случаях если он является экземпляром компонента React или элементом DOM. Для обоих этих случаев React имеет особый способ изменения.


Атрибут обратного вызова ref


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


Когда атрибут ref используется в элементе HTML, функция обратного вызова принимает базовый элемент DOM в качестве аргумента. Например, следующий код использует функцию обратного вызова, указанную в ref, для сохранения ссылки на узел DOM:


class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.focus = this.focus.bind(this);
  }

  focus() {
    // Установка фокуса на поле текстового ввода (input) с явным использованием исходного API DOM
    this.textInput.focus();
  }

  render() {
    // Использование обратного вызова `ref` для сохранения ссылки на поле текстового ввода (input)
    // как элемента DOM в this.textInput.
    return (
      <div>
        <input
          type="text"
          ref={(input) => { this.textInput = input; }} />
        <input
          type="button"
          value="Focus the text input"
          onClick={this.focus}
        />
      </div>
    );
  }
}

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


Использование обратного вызова ref для установки свойства в классе — это общепринятый шаблон для доступа к элементам DOM. Предпочтительный способ для установки свойства с использованием обратного вызова ref — тот который приведен в примере выше. Есть еще более короткий способ для реализации этого: ref={input => this.textInput = input}.


Если вы работали ранее с React, вы можете быть знакомы со старой версией API, когда атрибут ref является строкой, например, таким как "textInput" и узел DOM доступен как this.refs.textInput. Мы не рекомендуем пользоваться этим, т.к. со строчными ref есть некоторые проблемы, мы считаем их устаревшими и, возможно, они будут удалены в будущих версиях. Если в настоящий момент вы используете this.refs.myRefName, мы рекомендуем перейти к использованию описанного нами шаблона.


Когда атрибут ref используется в кастомном компоненте React, функция обратного вызова принимает смонтированный экземпляр компонента в качестве аргумента. Например, если мы захотели обернуть input из предыдущего примера в компонент CustomTextInput для симуляции клика сразу после монтирования:


class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.focus = this.focus.bind(this);
  }

  focus() {
    // Установка фокуса на поле текстового ввода (input) с явным использованием исходного API DOM
    this.textInput.focus();
  }

  render() {
    // Использование обратного вызова `ref` для сохранения ссылки на поле текстового ввода (input)
    // как элемента DOM в this.textInput.
    return (
      <div>
        <input
          type="text"
          ref={(input) => { this.textInput = input; }} />
        <input
          type="button"
          value="Focus the text input"
          onClick={this.focus}
        />
      </div>
    );
  }
}

class AutoFocusTextInput extends React.Component {
  componentDidMount() {
    this.textInput.focus();
  }

  render() {
    return (
      <CustomTextInput
        ref={(input) => { this.textInput = input; }} />
    );
  }
}

Нельзя использовать атрибут ref с компонентом, построенным на функции (stateless компонент), т.к. функция не имеет экземпляров. Однако, вы можете использовать атрибут ref внутри такого компонента:


function CustomTextInput(props) {
  // textInput задекларирован здесь, т.к. обратный вызов ref ссылается на него
  let textInput = null;

  function handleClick() {
    textInput.focus();
  }

  return (
    <div>
      <input
        type="text"
        ref={(input) => { textInput = input; }} />
      <input
        type="button"
        value="Focus the text input"
        onClick={handleClick}
      />
    </div>
  );  
}

Не злоупотребляйте обратными вызовами ref


Вашей первой мыслью может быть — что использование ref "превратит мечту в реальность" в вашем приложении. Если это так, то остановитесь и критически подумайте — верно ли расположены состояния в вашей иерархии компонентов. Часто возникает такая ситуация, что перерасположение состояния выше в иерархии компонентов, чем оно находится в настоящий момент, решает проблему. Смотрите руководство Подъем Состояния выше как пример этого.


Следующие части:



Предыдущие части:



Первоисточник: React — Advanced Guides — Refs and the DOM

Tags:
Hubs:
+20
Comments24

Articles