Рефс и ДОМ
Ссылки предоставляют способ доступа к узлам DOM или элементам React, созданным в методе рендеринга.
В типичном потоке данных React реквизиты являются единственным способом взаимодействия родительских компонентов со своими дочерними элементами. Чтобы изменить ребенка, вы перерисовываете его с новыми реквизитами. Однако есть несколько случаев, когда вам необходимо обязательно изменить дочерний элемент вне типичного потока данных. Дочерний объект, который нужно изменить, может быть экземпляром компонента React или элементом DOM. В обоих случаях React предоставляет аварийный люк.
Когда использовать ссылки
Есть несколько хороших вариантов использования ссылок:
- Управление фокусом, выделением текста или воспроизведением мультимедиа.
- Запуск императивных анимаций.
- Интеграция со сторонними библиотеками DOM.
Избегайте использования ссылок для всего, что может быть сделано декларативно.
Например, вместо предоставления методов open () и close () в компоненте Dialog, передайте ему реквизит isOpen.
Не злоупотребляйте ссылками
Ваше первое желание может заключаться в том, чтобы использовать ссылки, чтобы «заставить вещи происходить» в вашем приложении. Если это так, уделите немного времени и более критически подумайте о том, где должно находиться государство в иерархии компонентов. Часто становится ясно, что надлежащее место для «владения» этим состоянием находится на более высоком уровне в иерархии. См. Руководство по подъему состояния вверх для примеров этого.
Заметка
Приведенные ниже примеры были обновлены для использования API React.createRef (), представленного в React 16.3. Если вы используете более раннюю версию React, мы рекомендуем вместо этого использовать ссылки обратного вызова.
Создание ссылок
Ссылки создаются с использованием React.createRef () и прикрепляются к элементам React через атрибут refattribute. Ссылки обычно присваиваются свойству экземпляра при создании компонента, поэтому на них можно ссылаться по всему компоненту.
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return <div ref={this.myRef} />;
}
}
Доступ к ссылкам
Когда ссылка передается элементу рендеринга, ссылка на узел становится доступной в текущем атрибуте ссылки.
const node = this.myRef.current;
Значение ref отличается в зависимости от типа узла:
- Когда атрибут ref используется в элементе HTML, ссылка, созданная в конструкторе с помощью React.createRef (), получает базовый элемент DOM в качестве текущего свойства.
- Когда атрибут ref используется в пользовательском компоненте класса, объект ref получает подключенный экземпляр компонента в качестве текущего.
- Вы не можете использовать атрибут ref на компонентах функций, потому что у них нет экземпляров.
Приведенные ниже примеры демонстрируют различия.
,Добавление ссылки на элемент DOM
Этот код использует ссылку для хранения ссылки на узел DOM:
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
// create a ref to store the textInput DOM element
this.textInput = React.createRef();
this.focusTextInput = this.focusTextInput.bind(this);
}
focusTextInput() {
// Explicitly focus the text input using the raw DOM API
// Note: we're accessing "current" to get the DOM node
this.textInput.current.focus();
}
render() {
// tell React that we want to associate the <input> ref
// with the `textInput` that we created in the constructor
return (
<div>
<input
type="text"
ref={this.textInput} />
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
React назначит текущее свойство элементу DOM, когда компонент монтируется, и присвоит ему значение null, когда он монтируется. Обновления ref происходят перед методами жизненного цикла componentDidMount или componentDidUpdate.
Добавление ссылки на компонент класса
Если бы мы хотели обернуть описанный выше CustomTextInput, чтобы имитировать щелчок по нему сразу после монтирования, мы могли бы использовать ссылку для получения доступа к пользовательскому вводу и вызвать его метод focusTextInput вручную:
class AutoFocusTextInput extends React.Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
}
componentDidMount() {
this.textInput.current.focusTextInput();
}
render() {
return (
<CustomTextInput ref={this.textInput} />
);
}
}
Обратите внимание, что это работает, только если CustomTextInput объявлен как класс:
class CustomTextInput extends React.Component {
// ...
}
Ссылки и функциональные компоненты
Вы не можете использовать атрибут ref в компонентах функций, потому что они не имеют экземпляров:
function MyFunctionComponent() {
return <input />;
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
}
render() {
// This will *not* work!
return (
<MyFunctionComponent ref={this.textInput} />
);
}
}
Вы должны преобразовать компонент в класс, если вам нужен указатель на него, так же, как вы делаете, когда вам нужны методы или состояние жизненного цикла.
Однако вы можете использовать атрибут ref внутри компонента функции, если вы ссылаетесь на элемент DOM или компонент класса:
function CustomTextInput(props) {
// textInput must be declared here so the ref can refer to it
let textInput = React.createRef();
function handleClick() {
textInput.current.focus();
}
return (
<div>
<input
type="text"
ref={textInput} />
<input
type="button"
value="Focus the text input"
onClick={handleClick}
/>
</div>
);
}
Предоставление ссылок DOM на родительские компоненты
В редких случаях вам может потребоваться доступ к дочернему узлу DOM из родительского компонента. Это, как правило, не рекомендуется, поскольку нарушает инкапсуляцию компонентов, но иногда может быть полезно для активации фокуса или измерения размера или положения дочернего узла DOM.
Хотя вы можете добавить ссылку на дочерний компонент, это не идеальное решение, так как вы получите только экземпляр компонента, а не узел DOM. Кроме того, это не будет работать с функциональными компонентами.
Если вы используете React 16.3 или выше, мы рекомендуем использовать ref forwarding для этих случаев. Пересылка ссылок позволяет компонентам выставлять ссылки на любые дочерние компоненты как свои собственные. Вы можете найти подробный пример того, как представить дочерний узел DOM родительскому компоненту в документации пересылки ссылок.
Если вы используете React 16.2 или ниже, или если вам требуется больше гибкости, чем при пересылке ссылок, вы можете использовать этот альтернативный подход и явно передать ссылку как опору с другим именем.
Когда это возможно, мы не советуем выставлять DOM-узлы, но это может быть полезным выходным люком. Обратите внимание, что этот подход требует добавления некоторого кода в дочерний компонент. Если у вас нет абсолютно никакого контроля над реализацией дочернего компонента, последний вариант - использовать findDOMNode (), но в StrictMode он не рекомендуется и не рекомендуется.
Обратный звонок
React также поддерживает другой способ установки ссылок, называемый «обратными вызовами», который дает более точный контроль над тем, когда ссылки установлены и не установлены.
Вместо передачи атрибута ref, созданного createRef (), вы передаете функцию. Функция получает экземпляр компонента React или элемент HTML DOM в качестве аргумента, который можно сохранить и получить к нему доступ в другом месте.
В приведенном ниже примере реализован общий шаблон: использование обратного вызова ref для сохранения ссылки на узел DOM в свойстве экземпляра.
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
this.textInput = null;
this.setTextInputRef = element => {
this.textInput = element;
};
this.focusTextInput = () => {
// Focus the text input using the raw DOM API
if (this.textInput) this.textInput.focus();
};
}
componentDidMount() {
// autofocus the input on mount
this.focusTextInput();
}
render() {
// Use the `ref` callback to store a reference to the text input DOM
// element in an instance field (for example, this.textInput).
return (
<div>
<input
type="text"
ref={this.setTextInputRef}
/>
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
React вызывает обратный вызов ref с элементом DOM, когда компонент монтируется, и вызывает его с нулем, когда он монтируется. Ссылки гарантированно обновляются до запуска componentDidMount или componentDidUpdate.
Вы можете передавать ссылки на обратные вызовы между компонентами так же, как вы можете использовать ссылки на объекты, созданные с помощью React.createRef ().
function CustomTextInput(props) {
return (
<div>
<input ref={props.inputRef} />
</div>
);
}
class Parent extends React.Component {
render() {
return (
<CustomTextInput
inputRef={el => this.inputElement = el}
/>
);
}
}
В приведенном выше примере Parent передает свой обратный вызов ref в качестве реквизита inputRef в CustomTextInput, а CustomTextInput передает ту же функцию, что и специальный refattribute для <input>. В результате this.inputElement в Parent будет установлено на узел DOM, соответствующий элементу <input> в CustomTextInput.
Устаревший API: Строковые ссылки
Если вы раньше работали с React, вы, возможно, знакомы с более старым API, в котором атрибут refattribute представляет собой строку, например «textInput», а узел DOM доступен как this.refs.textInput. Мы не рекомендуем этого делать, потому что у строковых ссылок есть некоторые проблемы, они считаются устаревшими и, вероятно, будут удалены в одном из будущих выпусков.
Заметка
Если вы в настоящее время используете this.refs.textInput для доступа к ссылкам, мы рекомендуем вместо этого использовать либо шаблон обратного вызова, либо API createRef.
Предостережения с обратными ссылками
Если обратный вызов ref определен как встроенная функция, он будет вызываться дважды во время обновлений, сначала с нулем, а затем снова с элементом DOM. Это связано с тем, что при каждом рендеринге создается новый экземпляр функции, поэтому React необходимо очистить старый ref и установить новый. Вы можете избежать этого, определив функцию обратного вызова ref как связанный метод класса, но обратите внимание, что в большинстве случаев это не должно иметь значения.
Новый контент: Composer: менеджер зависимостей для PHP , R программирования