React по своей природе изолирует вас от прямой работы с DOM на 100%. Но нередко при интеграции сторонних компонентов, которые написаны не на React, возникает задача на прямой доступ к DOM. Также подобный механизм нужен для выделения текста, фокусов и проигрывания медиа.
React позволяет сделать это с помощью рефов (refs). Важно понимать, что в нормальной ситуации этот механизм не нужен и следует максимально избегать его использования.
Рассмотрим задачу по фокусировке на поле ввода:
See the Pen js_react_refs_focus by Hexlet (@hexlet) on CodePen.
ref — это атрибут компонента, значением которого должен быть объект, созданный в конструкторе через функцию React.createRef()
. Этот объект, в отличие от остальных данных, которые находятся в props
или state
, хранится как обычное свойство объекта. Имя свойства можно выбрать произвольно. Свойство current
этого объекта даёт доступ к элементу DOM, именно его можно использовать в componentDidMount
или componentDidUpdate
.
this.<имя свойства>.current
хранит внутри себя DOM-элемент того компонента, для которого был установлен ref. В примере выше это input: <input ref={this.textInput} />
. DOM-элемент попадает туда (внутрь current) уже после того, как текущий компонент будет встроен в реальный DOM, а значит им можно воспользоваться в указанных выше колбеках componentDidUpdate
и componentDidMount
.
Ниже приведён пример создания компонента обёртки над популярным jQuery-плагином Chosen.
See the Pen js_react_refs_dom by Hexlet (@hexlet) on CodePen.
Рефы также могут использоваться и на самописных компонентах, реализованных как классы.
Использование в реальном мире
С React удобно и легко работать до тех пор, пока мы остаёмся в рамках самого React, но большая часть существующих JS-библиотек взаимодействует с DOM напрямую, что фактически нивелирует преимущества React при их использовании. Например:
// https://github.com/kylefox/jquery-modal
$('#login-form').modal();
Включение в проект таких библиотек неизбежно приведёт к активному использованию методов жизненного цикла и сделает код сложным. По этой причине принято создавать так называемые компоненты-обёртки (врапперы), которые скрывают внутри себя все взаимодействие с DOM и наружу выставляют стандартный интерфейс React, а именно пропсы. Одной из таких задач, с взаимодействием с DOM, является изменение размера контейнера. Один из вариантов решения — компонент react-resizable. Посмотрите на работу этого компонента:
const Resizable = require('react-resizable').Resizable; // or,
const ResizableBox = require('react-resizable').ResizableBox;
// ES6
import { ResizableBox } from 'react-resizable';
// ...
render() {
return (
<ResizableBox width={200} height={200} minConstraints={[100, 100]} maxConstraints={[300, 300]}>
<span>Contents</span>
</ResizableBox>
);
}
Ничего в этом коде не напоминает о реальном DOM. Всё сводится к тому, что компонент оборачивается в ResizableBox
, который скрывает всю работу внутри себя. По такому же принципу устроены сотни и, может быть, тысячи других компонентов, которые доступны на GitHub. Вот некоторые из них:
- react-hotkeys
- react-stripe-elements (платёжный шлюз)
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.