20. useInsertionEffect
useInsertionEffect — это специализированная версия useLayoutEffect, предназначенная исключительно для библиотек CSS-in-JS. Он запускается до любых изменений в DOM и до того, как сработают useLayoutEffect.
Почему он существует?
Заголовок раздела «Почему он существует?»[Icon: Info] Основная проблема традиционных CSS-in-JS библиотек заключается в том, что когда стили добавляются или изменяются во время рендеринга (например, в useEffect), браузер вынужден пересчитывать стили (recalculate styles) для всего дерева элементов. Если это происходит часто, производительность падает.
useInsertionEffect позволяет библиотекам вставлять теги <style> в DOM до того, как браузер начнет вычислять макет (layout).
Порядок выполнения хуков
Заголовок раздела «Порядок выполнения хуков»- Render: React вычисляет, что должно быть в DOM.
- useInsertionEffect: Вставка стилей в DOM.
- useLayoutEffect: Чтение макета и синхронные изменения DOM.
- useEffect: Асинхронные эффекты (запросы, подписки).
graph TD A[Render Phase] --> B[useInsertionEffect] B --> C[DOM Mutations] C --> D[useLayoutEffect] D --> E[Browser Paints] E --> F[useEffect]Пример использования
Заголовок раздела «Пример использования»Обычно этот хук используется внутри абстракций CSS-in-JS. Вот упрощенный пример:
import { useInsertionEffect } from 'react';
// Гипотетическая функция для генерации и вставки стилейfunction useCSS(styleObject) { useInsertionEffect(() => { const styleTag = document.createElement('style'); styleTag.textContent = generateCSS(styleObject); document.head.appendChild(styleTag);
return () => { document.head.removeChild(styleTag); }; }, [styleObject]);}
function MyComponent() { useCSS({ color: 'red', fontSize: '20px' }); return <div className="dynamic-style">Привет, мир!</div>;}Ключевые ограничения
Заголовок раздела «Ключевые ограничения»- Только для библиотек: Если вы не пишете свою CSS-in-JS библиотеку, вам почти наверняка не нужен этот хук.
- Нет доступа к refs: Внутри
useInsertionEffectвы не можете получить доступ кref.currentэлементов вашего компонента, так как DOM еще не обновлен. - Только на клиенте: Как и другие эффекты, он не работает при серверном рендеринге (SSR).
[Icon: Alert-Triangle] Важно: Не используйте этот хук для побочных эффектов, которые не связаны со стилями. Для обычных задач используйте useEffect или useLayoutEffect.
🔗 Полезные ссылки
Заголовок раздела «🔗 Полезные ссылки»- [string
. Если ширина контейнера заголовка (например,div) становится меньше 300px, текст должен усекаться и добавляться многоточие (…`). Изменение должно происходить плавно и без мерцания при изменении размера окна браузера.- Подсказка: Вам понадобится
useRefдля элемента заголовка иResizeObserverдля отслеживания изменений размера, который вы будете подключать/отключать вuseLayoutEffectилиuseEffect. Но само применение усечения, зависящее от размеров, лучше делать черезuseLayoutEffect.
- Подсказка: Вам понадобится
- Адаптивный тултип (всплывающая подсказка):
Создайте компонент
Tooltip(который рендерится внутриButtonилиHoverAreaкомпонента). Когда пользователь наводит курсор на элемент, появляется тултип.Tooltipдолжен позиционироваться относительно элемента, на который навели, и гарантировать, что он не выходит за пределы видимой области экрана (viewport). Пересчет позиции должен происходить вuseLayoutEffectпри первом появлении тултипа или при скролле/ресайзе страницы.- Подсказка:
getBoundingClientRect()элемента-триггера иwindow.innerWidth/window.innerHeightдля viewport. ИспользуйтеuseStateдля хранения позиции тултипа (top,left).
- Подсказка:
### 💡 Совет
Заголовок раздела «### 💡 Совет»Используйте useLayoutEffect только тогда, когда вам абсолютно необходимо синхронно взаимодействовать с DOM после его изменения React](/react/use-layout-effect/)
Практика
Заголовок раздела «Практика»Попробуйте примеры в интерактивном редакторе: