#7 React - refs

poster
В этом уроке мы разберем как обратится к DOM элементу в React с помощью атрибута ref, почему его нужно использовать с осторожностью и какие возможности он дает
Понравилось? Поделитесь с друзьями!
Понравилось?
Поделитесь с друзьями!
Комментарии
Текст видео

Всем привет. В этом уроке мы разберем с вами что такое refs в React. В прошлых уроках мы разобрали с вами два типа данных в React: props и state. Нам осталось разобрать еще один тип данных в React. Это refs. Он позволяет обращатся к конкретному DOM елементу компонента.

Это полезно в нескольких случаях. Например, когда вы хотите прочитать значение елемента без React или навесить jQuery библиотеку на елемент. Или вызвать какой-то нативный метод - например focus.

Давайте попробуем. Не так давно в React изменили синтаксис работы с refs и теперь он вот такой.

Давайте создадим input и button

import React, { Component } from 'react';

class App extends Component {
  render() {
    return (
      <div>
        <input type="text" placeholder="test" />
        <button>Submit</button>
      </div>
    );
  }
}

export default App;

Если мы посмотрим в браузер, то увидим, что наша форма отрисовалась.

Добавим атрибут onClick и прибайндим метод this.submit в нашему контексту.

Для этого навешиваем onClick евент

<button onClick={this.submit.bind(this)}>Submit</button>

и добавляем submit метод

submit() {
  console.log('submit');
}

Если мы посмотрим в браузер, то наша функция submit вывела консоль лог при клике.

Теперь для того, чтобы получить значение DOM елемента input нужно навесить на него вот такую конструкцию.

<input type="text" placeholder="test" ref={(input) => this.testInput = input} />

Здесь мы указали атрибут ref, который является функцией и присваивает input в переменную this.testInput. React вызвает ref callback, когда наш компонент рендерится. Это обычный паттерн в React как получить доступ к DOM елементам.

Теперь в нашей функции submit мы можем вывести this.testInput.

submit() {
  console.log('submit', this.testInput);
}

Как мы видим, в консоль нам вывелся DOM елемент. Теперь мы можем делать с ним что угодно. Например, узнать его значение в данный момент.

console.log('submit', this.testInput.value);

Если мы введем что-то в input и нажмем submit, то в консоль выведется значение input.

Ref отличный способ доступа к DOM елементам, но его нужно применять с осторожностью. Нужно помнить, что это не React way, а просто возможность доступа к DOM елементам. Всегда лучше использовать state, props если это возможно вместо refs, так как они поддерживают правильный флоу данных в приложении, а refs нет.

Только зарегистрированные пользователи могут оставлять комментарии.  Войдите, пожалуйста.
Petr Pozhoga
5 лет назад
Здравствуйте, Monster, а как узнать когда DOM уже отрендерился и мне нужно узнать, что то из стилей ? По идее должен быть какой то хук, но я его не нашел.
monsterlessons
5 лет назад
Добрый день. Вам нужен componentDidMount
Petr Pozhoga
5 лет назад
Я тоже так думал но когда компонент маунтится и я хочу узнать someElementRef.getBoundingClientRect().width у меня происходит ошибка
monsterlessons
5 лет назад
Если вы делаете что-то через ref, то данные будут доступны только после первого рендера <div ref={(node) => calcHeight(node)}> calcHeight(node) { if (node) { } }
Petr Pozhoga
5 лет назад
Спасибо большое, возможно кто то не захочет юзать стрелочные функции, можно написать вот так <div ref={this.calcHeight}> calcHeight(node) { if (node) { } }
Petr Pozhoga
5 лет назад
Возникла следующая проблема, я узнаю стиль элемента ref как описано выше, только ширина определяется не верно. node.getBoundingClientRect().width - значения на 5-7 пикселей меньше Почему так ?
Petr Pozhoga
5 лет назад
Возникла следующая проблема, я узнаю стиль элемента ref как описано выше, только ширина определяется не верно(только при первом рендеринге страницы). node.getBoundingClientRect().width - значения на 5-7 пикселей меньше Почему так ? _____________ Кстати я не могу удалить / редактировать свой коммент выше
monsterlessons
5 лет назад
Без понятия. Нужно дебажить. Попробуйте завернуть код в setTimeout(() => {}, 0) возможно ваш элемент не успевает отрендериться.
Moe Green
6 лет назад
Не нашел нигде места, как только спросить здесь, хотя это и не совсем по теме. Подскажите, что Вы думаете по поводу таких фреймворков как KeystoneJS (https://github.com/keystonejs/keystone) или AdonisJS (https://github.com/adonisjs/adonis-framework)? В первую очередь в плане востребованности (работы)?
Moe Green
6 лет назад
а почему Вы постоянно используете "подвязывание" функций к this через .bind(this)? разве не проще изначально создавать функцию стрелочной и тогда не будет проблем с this?
monsterlessons
6 лет назад
С stateless компонентах я так и делаю. А в классах смешивать стрелочные функции и методы мне не нравится.
Moe Green
6 лет назад
Поправьте меня. Вы здеь показали использование ref в виде callback-функции. Но есть еще один вид ref - строковая переменная. Ref в виде функции используется в функциональных компонентах, а в виде строковой переменной - в statefull компонентах. Так?
monsterlessons
6 лет назад
Refs в виде строк это легаси уже. Их не нужно использовать. Всегда только функции. Пруф: https://reactjs.org/docs/refs-and-the-dom.html
Moe Green
6 лет назад
Ясно. Значит, Eve Porcello с его "Learning React" меня слегка подвел )
Moe Green
6 лет назад
Непонятно - переменная this.testInput - как она появилась и где существует. Подскажете?
monsterlessons
6 лет назад
Она появилась, когда мы указали ref на элементе. Это увидел Vue и добавил нам в this ссылку на DOM элемент.
Moe Green
6 лет назад
Вы хотели сказать - React? )
monsterlessons
6 лет назад
Упс :D Там у меня уроки с Refs по Vue тоже есть. Тогда ответ выше неверный. this нам доступен при рендере и мы просто можем в любую переменную this записать аргумент функции внутри ref.
Moe Green
6 лет назад
можно сказать так - мы можем динамически, "на ходу" создать любую переменную в this и использовать ее дальше по коду. я правильно понимаю? )
monsterlessons
6 лет назад
Именно. Но нужно учитывать, что во время первого рендера эта переменная будет undefined, пока она не засетится.
Moe Green
6 лет назад
ок )
Rustam Apaev
7 лет назад
Знаете, когда я 2 года назад впервые узнал о реакте, я хотел реализовать одну идейку. С воспроизведением аудио . И я пытался на элемент <audio ref = /> через реф навесить воспроизведение и прочее. (хотел субтитры пофразово воспроизводить) . Тогда еще был был старый синтаксис , когда туда строка передавалась. Но я так и не разобрался и не смог получить управление аудио элементом, хотя очень упорно читал документацию)). Сейчас, благодаря этому уроку, за 5 минут, я уже смог запустить play & pause. А вообще дальше мне надо следить за текущим временем воспроизведения audioElement.currentTime и переключаться между фразами (секунды которых заданы). Я надеюсь увижу как это делать в уроке "Функциональные компоненты", а если не увижу, то вы мне подскажете, в каком направлении двигаться ;-)
monsterlessons
7 лет назад
Рад, что видео помогли. Я и так могу подсказать. Функциональные компоненты не нужно применять, когда вы хотите работать с нативными методами или вызывать различные нативные функции компонента. Просто в конструкторе навешивайте евенты из чистого javascript, например, playback finished/started и меняйте state елемента, который будет автоматически перерисовывать react елементы.
Rustam Apaev
7 лет назад
Спасибо. Да, точно, работает ) <audio controls src="audio/Alice/mp3/Alice_In_Wonderland_ch_01.mp3" ref={ (media) => this.mediaElement = media} onTimeUpdate={this.handlerAudioTimeUpdate.bind(this)} /> Я по большей части все реализовал в ангуляре. Просто в какой-то момент надоел он , и приложение стало тормозить, а я не мог найти причину... Вообще думал на vuejs переходить, но потом мне Meteor понравился. А он еще со Vue не очень хорошо интегрирован. Поэтому решил вернуться к реакту. Такой долгий путь у меня получился)) и всё равно постоянно в сомнениях.
monsterlessons
7 лет назад
Можете посмотреть мое видео про сравнение фреймворков https://monsterlessons.com/project/lessons/kakoj-javascript-frejmvork-vybrat Для себя я выбираю React из-за хорошего сервер-сайд рендеринга, огромного количества дополнительных пакетов и отсутствия 100500 ненужных и выдуманных сущностей, как в Angular 2. Vuejs хорош, но он уже вряд ли выстрелит. А если его использовать сейчас, то количество дополнительных и нужных библиотек сильно ограничено.
Moe Green
6 лет назад
"Vuejs хорош, но он уже вряд ли выстрелит ..." - к сожалению, это скорее всего так.
Rustam Apaev
7 лет назад
меня немного запутало "этот инпут" непонятно , то ли речь идет об аргументе в стрелочной функции, то ли об html элементе. Но потом прочитал ещё и переслушал и понял, что аргумент это и есть html элемент) если бы он назывался по другому , может понятнее стало бы )