ReactJS - Refs и DOM

Здравствуйте, будущие разработчики React! Сегодня мы погрузимся в увлекательную тему, которая поможет вам взаимодействовать с элементами DOM в ваших приложениях React. Закрепите ремни,因为我们 собираемся исследовать мир Refs и DOM!

ReactJS - Refs and the DOM

Что такое Refs?

Прежде чем мы углубимся в детали, давайте поймем, что такое Refs. В React "Ref" - это сокращение от "reference" (ссылка). Это как дать конкретному элементу бирку с именем, чтобы вы могли легко найти его позже. Представьте, что вы на большом празднике и хотите следить за своим лучшим другом. Вы можете дать ему specialную шляпу или уникальную бирку. Это essentially то, что делают Refs в React - они помогают вам следить за конкретными элементами.

Почему нам нужны Refs?

Вы можете задаться вопросом: "Почему мы не можем просто использовать обычный JavaScript для выбора элементов?" Ну, в React мы стараемся избегать прямого манипулирования DOM (Document Object Model), потому что React имеет свой эффективный способ обновления интерфейса. Однако бывают случаи, когда нам нужно выйти за пределы декларативной парадигмы React и работать напрямую с элементами DOM. Вот где Refs могут пригодиться!

Создание Refs с помощью createRef()

Давайте начнем с того, как создаем Ref в React. Мы используем метод createRef().

Сигнатура метода createRef

Сигнатура createRef() довольно проста:

React.createRef()

Вот и все! Никаких параметров, никаких сложностей. Он возвращает пустой объект с единственным свойством: current. Initially, это свойство установлено в null.

Давайте посмотрим пример:

class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}

render() {
return <div ref={this.myRef} />;
}
}

В этом примере мы создаем Ref в конструкторе и присваиваем его this.myRef. Затем в методе render мы attach этого Ref к элементу div с помощью атрибута ref.

Применение ref

Теперь, когда мы создали наш Ref, давайте посмотрим, как мы можем его использовать. Есть несколько способов применения Ref:

1. Refs на DOM элементах

Самый распространенный случай - применить Ref к DOM элементу:

class AutoFocusInput extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}

componentDidMount() {
this.inputRef.current.focus();
}

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

В этом примере мы создаем Ref для элемента ввода. После того как компонент монтируется, мы используем Ref для автоматического фокуса на вводе. Свойство current Ref дает нам доступ к реальному узлу DOM.

2. Refs на классовых компонентах

Вы также можете использовать Refs с классовыми компонентами:

class AutoScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}

componentDidUpdate() {
const node = this.listRef.current;
node.scrollToItem(0);
}

render() {
return <MyListComponent ref={this.listRef} />;
}
}

В этом случае this.listRef.current будет указывать на экземпляр класса MyListComponent.

3. Refs и функциональные компоненты

Функциональные компоненты не могут быть даны Refы напрямую, но вы можете использовать функцию forwardRef для передачи Refов:

const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));

class MyComponent extends React.Component {
constructor(props) {
super(props);
this.buttonRef = React.createRef();
}

render() {
return <FancyButton ref={this.buttonRef}>Нажми меня!</FancyButton>;
}
}

В этом примере FancyButton использует forwardRef для передачи Refа к реальному элементу按钮а.

Сценарии использования createRef

Теперь, когда мы знаем, как создавать и применять Refs, давайте рассмотрим некоторые распространенные сценарии использования:

1. Управление фокусом, текстовым выделением или воспроизведением медиа

class TextInput extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}

focusTextInput = () => {
this.inputRef.current.focus();
}

render() {
return (
<div>
<input type="text" ref={this.inputRef} />
<button onClick={this.focusTextInput}>Фокус на ввод</button>
</div>
);
}
}

Этот компонент позволяет нам программно фокусировать ввод при нажатии на кнопку.

2. Запуск imperативных анимаций

class Animator extends React.Component {
constructor(props) {
super(props);
this.elementRef = React.createRef();
}

animate = () => {
this.elementRef.current.classList.add('animated');
}

render() {
return (
<div>
<div ref={this.elementRef}>Анимируй меня!</div>
<button onClick={this.animate}>Начать анимацию</button>
</div>
);
}
}

Здесь мы используем Ref для добавления CSS класса к элементу, что запускает анимацию.

3. Интеграция с third-party DOM библиотеками

class MapComponent extends React.Component {
constructor(props) {
super(props);
this.mapRef = React.createRef();
}

componentDidMount() {
const mapLibrary = new FancyMapLibrary();
mapLibrary.createMap(this.mapRef.current);
}

render() {
return <div ref={this.mapRef} style={{width: '100%', height: '400px'}} />;
}
}

В этом примере мы используем Ref для предоставления third-party map библиотеке доступа к DOM узлу, где она может отрендерить карту.

Заключение

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

Помните, с большой силой приходит большая ответственность. Используйте Refs wisely, и ваши приложения React будут вам благодарны!

Вот quick reference таблица методов, о которых мы говорили:

Метод Описание Пример
React.createRef() Создает ref объект this.myRef = React.createRef();
ref атрибут Присоединяет ref к React элементу <div ref={this.myRef} />
forwardRef Позволяет функциональным компонентам принимать refs const FancyButton = React.forwardRef((props, ref) => ...)

Счастливого кодирования, и пусть ваши Refs всегда будут актуальными!

Credits: Image by storyset