useInsertionEffect
useInsertionEffect
позволяет добавлять элементы в DOM, до срабатывания эффектов, вызванных useLayoutEffect
и useEffect
.
useInsertionEffect(setup, dependencies?)
Справочник
useInsertionEffect(setup, dependencies?)
Вызовите useInsertionEffect
, чтобы вставить стили до того, как сработают любые эффекты, которым может потребоваться чтение разметки:
import { useInsertionEffect } from 'react';
// Внутри вашей бибилиотеки CSS-in-JS
function useCSS(rule) {
useInsertionEffect(() => {
// ... вставьте свои теги <style> сюда ...
});
return rule;
}
Параметры
-
setup
: Функция с логикой вашего эффекта. Ваша setup-функция, опционально, может возвращать функцию очистки. Перед тем, как ваш компонент добавится в DOM, React запустит вашу setup-функцию. После каждого повторного рендера с изменёнными зависимостями, React запустит функцию очистки (если вы её предоставили) со старыми значениями, а затем запустит вашу setup-функцию с новыми значениями. Перед тем как ваш компонент удалится из DOM, React запустит функцию очистки. -
dependencies
: Список всех реактивных значений, на которые ссылается код функцииsetup
. К реактивным значениям относятся пропсы, состояние, а также все переменные и функции, объявленные непосредственно в теле компонента. Если ваш линтер настроен для использования с React, он проверит, что каждое реактивное значение правильно указано как зависимость. Список зависимостей должен иметь постоянное количество элементов и быть записан примерно так:[dep1, dep2, dep3]
. React будет сравнивать каждую зависимость с предыдущим значением, используя алгоритм сравненияObject.is
. Если не указать зависимости вообще, то эффект будет запускаться заново после каждого повторного рендера компонента.
Возвращаемое значение
useInsertionEffect
возвращает undefined
.
Предостережения
- Эффекты выполняются только на клиенте. Они не выполняются во время серверного рендера.
- Вы не можете обновить состояние изнутри
useInsertionEffect
. - К моменту выполнения
useInsertionEffect
ссылки ещё не прикреплены, а DOM ещё не обновлён. useInsertionEffect
может выполняться как до, так и после обновления DOM. Не следует полагаться на то, что DOM будет обновлён в какой-то конкретный момент.- В отличие от других типов эффектов, которые запускают очистку для каждого эффекта, а затем установку для каждого эффекта,
useInsertionEffect
будет запускать очистку и установку поочерёдно для каждого компонента. Это приводит к “переплетению” функций очистки и установки.
Использование
Внедрение динамических стилей из библиотек CSS-in-JS
Традиционно для стилизации компонентов React используется обычный CSS.
// В вашем JS-файле:
<button className="success" />
// В вашем CSS-файле:
.success { color: green; }
Некоторые команды предпочитают создавать стили непосредственно в коде JavaScript, вместо того чтобы писать файлы CSS. Обычно это требует использования библиотеки или инструмента CSS-in-JS. Существует три распространённых подхода к CSS-in-JS:
- Статическая экстракция в файлы CSS с помощью компилятора
- Встроенные стили, например,
<div style={{ opacity: 1 }}>
- Внедрение тегов
<style>
во время выполнения.
Если вы используете CSS-in-JS, мы рекомендуем комбинацию первых двух подходов (файлы CSS для статических стилей, встроенные стили для динамических стилей). Мы не рекомендуем внедрение тегов <style>
во время выполнения по двум причинам:
- Внедрение во время выполнения заставляет браузер пересчитывать стили гораздо чаще.
- Внедрение может быть очень медленным, если это происходит в неподходящее время жизненного цикла React.
Первая проблема неразрешима, но useInsertionEffect
помогает решить вторую проблему.
Вызовите useInsertionEffect
, чтобы вставить стили до срабатывания любых эффектов разметки:
// Внутри вашей CSS-in-JS библиотеки
let isInserted = new Set();
function useCSS(rule) {
useInsertionEffect(() => {
// Как было объяснено ранее, мы не рекомендуем внедрение тегов <style> во время выполнения.
// Но если вам нужно это сделать, то важно использовать для этого useInsertionEffect.
if (!isInserted.has(rule)) {
isInserted.add(rule);
document.head.appendChild(getStyleForRule(rule));
}
});
return rule;
}
function Button() {
const className = useCSS('...');
return <div className={className} />;
}
Схожим образом useEffect
, useInsertionEffect
не запускается на сервере. Если вам нужно собрать информацию о том, какие CSS-правила были использованы на сервере, вы можете сделать это во время рендера:
let collectedRulesSet = new Set();
function useCSS(rule) {
if (typeof window === 'undefined') {
collectedRulesSet.add(rule);
}
useInsertionEffect(() => {
// ...
});
return rule;
}
Deep Dive
Если вы вставляете стили во время рендеринга, и React обрабатывает неблокирующее обновление, браузер будет пересчитывать стили на каждом кадре во время рендеринга дерева компонентов, что может быть чрезвычайно медленным.
useInsertionEffect
лучше, чем вставка стилей во время useLayoutEffect
или useEffect
потому что это гарантирует, что к тому времени, как другие эффекты запускаются в ваших компонентах, теги <style>
уже будут вставлены. В противном случае расчёты компоновки в обычных эффектах будут неверными из-за устаревших стилей.