0Pricing
React Academy · Урок

Измерение элементов DOM с помощью useLayoutEffect

Считывайте размеры, позиции и смещения прокрутки элементов после компоновки, но до отрисовки, чтобы избежать мерцания

«Измерение элементов DOM с помощью useLayoutEffect» — бесплатный урок React Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения React Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс React Academy содержит 4 уроков всего.

Обзор getBoundingClientRect

element.getBoundingClientRect() возвращает объект DOMRect с размером и положением элемента относительно области просмотра: top, right, bottom, left, width и height. Для возврата точных значений браузер выполняет расчёт компоновки, поэтому вызывайте этот метод экономно.

Проблема чтения в useEffect

Если прочитать getBoundingClientRect() в useEffect, браузер уже выполнил отрисовку. Если затем установить состояние на основе измерения, React повторно отрендерит компонент, и браузер снова выполнит отрисовку. Пользователь может ненадолго увидеть элемент в неправильном положении или с неправильным размером, прежде чем исправление появится во время второй отрисовки.

Почему useLayoutEffect решает эту проблему

Чтение измерений в useLayoutEffect происходит после изменений DOM, но до отрисовки. Любое обновление состояния, вызванное измерением, заставляет React синхронно повторно отрендерить компонент и зафиксировать исправленный DOM — всё это до того, как браузер что-либо отрисует. Пользователь видит только окончательный правильный результат за один цикл отрисовки.

Позиционирование всплывающей подсказки

Всплывающая подсказка должна появляться рядом с элементом, который её вызывает. Измерьте положение этого элемента в useLayoutEffect с помощью getBoundingClientRect(), вычислите абсолютное положение подсказки и сохраните его в состоянии. Подсказка отобразится в правильном месте уже при первой отрисовке, без заметного скачка из неправильного исходного положения.

Анимация элемента: чтение исходного размера

Чтобы анимировать переход элемента от его естественного, неограниченного размера к фиксированному, необходимо узнать естественный размер до применения ограничения. Прочитайте высоту элемента в useLayoutEffect до применения стиля анимации, сохраните её в состоянии, а затем используйте как начальное значение ключевого кадра для перехода CSS.

Высота закреплённой шапки

Если на странице есть закреплённая шапка, содержимому страницы нужен верхний внутренний отступ, равный высоте шапки, чтобы оно не оказалось скрытым за ней. Измерьте высоту шапки в useLayoutEffect с помощью ссылки на элемент: headerRef.current.getBoundingClientRect().height. Установите это значение как paddingTop контейнера содержимого. Компоновка будет правильной уже при первом рендеринге.

Обновление состояния вызывает синхронный повторный рендеринг

Когда вы вызываете setState внутри useLayoutEffect, React немедленно запускает ещё один цикл рендеринга и фиксации в том же синхронном блоке. Этот повторный рендеринг также запускает его useLayoutEffect. Будьте осторожны и не создайте бесконечный цикл: обновляйте состояние только в том случае, если новое измерение отличается от текущего значения состояния.

SSR: измерения возвращают нулевые значения

На сервере элементы DOM не существуют, поэтому getBoundingClientRect() вызовет исключение или вернёт нулевые значения. Защитите свой useLayoutEffect проверкой: if (typeof window === 'undefined') return;. В приложениях с SSR может потребоваться выполнить гидратацию с размером-заполнителем, а затем измерить элемент после гидратации на клиенте.

Непрерывное отслеживание с ResizeObserver

Однократное измерение с помощью useLayoutEffect даёт размер на момент монтирования. Для отслеживания изменений размера при изменении размера окна, динамическом содержимом или изменениях CSS используйте вместо этого ResizeObserver. Он вызывает обратный вызов при каждом изменении размера элемента, поэтому лучше подходит для адаптивных компонентов.

Как избежать лишних измерений

Если нескольким эффектам нужно одно и то же измерение, вычислите его один раз и передайте через контекст или свойства. Вычисление одного и того же значения getBoundingClientRect() в нескольких вызовах useLayoutEffect приводит к нескольким синхронным чтениям компоновки, каждое из которых относительно затратно. По возможности объединяйте измерения.

Момент заполнения ссылки при использовании useLayoutEffect

Ссылки заполняются до запуска эффектов. Когда срабатывает useLayoutEffect, гарантируется, что ref.current указывает на элемент DOM. Именно поэтому работает следующий шаблон: useLayoutEffect(() => { const rect = ref.current.getBoundingClientRect(); ... }, []). Внутри эффекта компоновки у смонтированного компонента ссылка никогда не бывает пустой.

Момент срабатывания getBoundingClientRect

Почему лучше вызывать getBoundingClientRect() в useLayoutEffect, а не в useEffect?

Повторение урока: измерение элементов DOM

Используйте getBoundingClientRect() в useLayoutEffect, чтобы считывать измерения DOM после изменений, но до отрисовки. Обновления состояния на основе этих измерений вызывают синхронный повторный рендеринг, включённый в ту же отрисовку, и предотвращают мерцание. Для SSR установите защиту с помощью проверки typeof window. Для непрерывного отслеживания размера отдавайте предпочтение ResizeObserver.

Часто задаваемые вопросы

Урок «Измерение элементов DOM с помощью useLayoutEffect» бесплатный?

Да — полный текст урока «Измерение элементов DOM с помощью useLayoutEffect» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс React Academy, подпишись на CoddyKit PRO. Курс React Academy содержит 4 уроков всего.

Чему я научусь в уроке «Измерение элементов DOM с помощью useLayoutEffect»?

Считывайте размеры, позиции и смещения прокрутки элементов после компоновки, но до отрисовки, чтобы избежать мерцания Ты практикуешь React Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать React Academy?

Предыдущий опыт не требуется. React Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Измерение элементов DOM с помощью useLayoutEffect»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке React Academy?

Да. Каждый урок React Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Фаза отображения и фиксация DOM
  2. Когда срабатывает useLayoutEffect по сравнению с useEffect
  3. Измерение элементов DOM с помощью useLayoutEffect
  4. Как избежать перерасчёта компоновки и визуального мерцания
← Назад к React Academy