Продолжение серии переводов раздела "Продвинутые руководства" (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