Эта статья является одной из серии статей на тему «подкова · React», и в будущем будет запущено больше тем.
иди ко мнеGitHub repoЧитать полную статью
иди ко мнеличный блогПолучите непревзойденный опыт чтения
Смысл существования React в том, что состояние отделено от UI, чтобы разработчики не знали, что есть DOM, вне зависимости от Вея и Джина.
Однако некоторые состояния нельзя отделить от пользовательского интерфейса, например фокус формы, сложные анимации и т. д.
Как сделать? Пока React полностью не контролирует DOM, он по-прежнему оставляет лазейку для разработчиков.
this.refs
💀 Это API устарело в React.
Когда создается экземпляр каждого компонента класса, монтируется атрибут refs, который используется для хранения ссылок DOM.
Передача значения в элементе DOM представляет собой строкуref
атрибут, разработчик получает ссылку на элемент DOM, мы можемthis.refs
Найдите его под объектом.
Поскольку он должен получить ссылку на элемент DOM, он должен дождаться монтирования компонента, прежде чем им можно будет манипулировать.
Однако React больше не рекомендует такой способ написания. Основная причина в том, что это потребляет производительность, потому что UI будет подвергаться множеству обновлений, а ссылка на строку не может автоматически отслеживать изменения DOM, и React должен выполнять некоторую дополнительную обработку.
Возможно, в будущей версии мы не сможем увидеть атрибут refs экземпляра.
import React, { Component } from 'react';
class App extends Component {
componentDidMount() {
this.refs.textInput.focus();
}
render() {
return (
<input type="text" ref="textInput" />
);
}
}
export default App;
callback
React также поддерживает получение ссылки на элемент DOM с обратным вызовом.
Но помните, обратные вызовы не могут быть записаны какel => this.refs.textInput = el
,потому чтоthis.refs
Напрямую написать нельзя.
import React, { Component } from 'react';
class App extends Component {
componentDidMount() {
this.textInput.focus();
}
render() {
return (
<input type="text" ref={el => this.textInput = el} />
);
}
}
export default App;
Конечно, обратные вызовы обладают огромной силой, например, они могут проходить сквозь стены.
Обратный вызов по-прежнему используется для получения ссылки на элемент DOM, но на этот раз обратный вызов передается от родительского компонента через свойства.
После монтирования дочернего компонента выполняется обратный вызов ref, и родительский компонент получает ссылку на элемент DOM дочернего компонента.
import React, { Component } from 'react';
import Search from './Search';
class App extends Component {
getInputRef = (ref) => {
this.node = ref;
}
render() {
return (
<Search ref={this.getInputRef} />
);
}
}
export default App;
import React from 'react';
const Search = (props) => (
<input type="text" ref={props.getInputRef} />
);
export default Search;
createRef
👽 Это API, выпущенный React v16.3.0.
createRef
Роль заключается в создании объекта ref.
первыйcreateRef
Результат выполнения возвращается в свойство экземпляра, а затем через свойство экземпляра получается ссылка на элемент DOM.
Меры предосторожности:
-
createRef
Действие инициализации должно быть выполнено до монтирования компонента.Если оно инициализировано после монтирования компонента, ссылка на элемент DOM не может быть получена. - Фактическая ссылка на элемент DOM находится в текущем свойстве.
import React, { Component, createRef } from 'react';
class App extends Component {
textInput = createRef();
componentDidMount() {
this.textInput.current.focus();
}
render() {
return (
<input type="text" ref={this.textInput} />
);
}
}
export default App;
По необъяснимым причинам, если вы хотите получить ссылку на подкомпонент, этот подкомпонент должен быть компонентом класса.
Потому что то, что вы получаете, на самом деле является экземпляром дочернего компонента, а функциональный компонент не имеет экземпляра.
Из всех способов получить ссылки ref, если вы хотите получить дочерний компонент вместо элемента DOM, дочерний компонент не может быть функциональным компонентом.
import React, { Component, createRef } from 'react';
import Child from './Child';
class App extends Component {
childRef = createRef();
render() {
return (
<Child ref={this.childRef} />
);
}
}
export default App;
forwardRef
👽 Это API, выпущенный React v16.3.0.
Используя обратные вызовы, можно получить ссылку на элемент DOM дочернего компонента, но этот метод, в конце концов, является хаком.
Столь интимный React дает нам боевые искусства приличия, которые могут проникать сквозь стены.
В том, как написан родительский компонент, нет ничего особенного, но на этот разcreateRef
Возвращаемый результат — это не элемент DOM, переданный самому себе, а дочерний компонент.
Ключ лежит в подкомпоненте, а подкомпонент передает себя как параметр вforwardRef
, а затем дочерний компонент получает параметр ref вне параметра props, а затем присваивает параметр ref атрибуту ref элемента DOM.
Нашли?forwardRef
Действуя как передатчик, он на самом деле является компонентом контейнера.
прямой проход, который называетсяforwardRef
причина.
Особое внимание требуется при использованииforwardRef
, компонент должен быть функциональным компонентом. Причина может заключаться в том, что React не хочет нарушать систему параметров компонентов класса.
Эй, разве раньше не говорилось, что вы не можете использовать функциональные компоненты при получении ссылки на компонент?
Если присмотреться, то между ними есть существенные различия: здесь по-прежнему получаются DOM-элементы, но они кросс-уровневые.
import React, { Component, createRef } from 'react';
import Search from './Search';
class App extends Component {
textInput = createRef();
componentDidMount() {
this.textInput.current.focus();
}
render() {
return (
<Search ref={this.textInput} />
);
}
}
export default App;
import React, { forwardRef } from 'react';
const Search = forwardRef((props, ref) => (
<input type="text" ref={ref} />
));
export default Search;
Поскольку это кросс-уровень, можете ли вы играть покрупнее?
конечно может.
В самом деле, как толькоforwardRef
Обернутый дочерний компонент получает параметр ref и может продолжать передавать ref вниз. То, что передается через, конечно же, реквизит!
После этого ref становится обычным реквизитом, и вы можете отправить его в свое распоряжение, пока он не будет смонтирован в атрибуте ref DOM-элемента.
Я не нашел, и я не буду различать компоненты класса и функциональные компоненты, потому что и компоненты класса, и функциональные компоненты могут получать реквизиты. Его задача — просто помочь предку в неизвестном количестве поколений прикрепить эту конкретную опору к конкретному элементу DOM.
Фактически, обратный вызов ref также может передаваться по нескольким уровням, принцип тот же, что и выше.
import React, { Component, createRef } from 'react';
import Search from './Search';
class App extends Component {
textInput = createRef();
render() {
return (
<Search ref={this.textInput} />
);
}
}
export default App;
import React from 'react';
import Input from './Input';
const Search = forwardRef((props, ref) => (
<Input inputRef={ref} />
));
export default Search;
import React, { Component } from 'react';
class Input extends Component {
render() {
return (
<input type="text" ref={this.props.inputRef} />
);
}
}
export default Input;
Реагировать темы на первый взгляд