Svelte

Жизненный цикл: onMount и `$effect`

Компоненту графика нужно инициализировать стороннюю библиотеку рисования, но только когда узел уже в DOM, иначе рисовать не на чем. А при уходе со страницы график надо корректно остановить, чтобы не утекли таймеры. Это классические точки жизненного цикла: после монтирования и перед удалением. onMount даёт первую, onDestroy - вторую. В Svelte 5 многое из того, что раньше делали через лайфсайкл-хуки, теперь решает руна `$effect`, которая реагирует на состояние и сама очищает за собой.

  • Инициализация графика или карты после монтирования через onMount, когда DOM-узел уже существует
  • Подписка на сокет или интервал и её снятие при удалении компонента
  • Чтение размеров элемента сразу после появления на странице
  • Эффект, который перезапрашивает данные при изменении id из состояния
  • Установка фокуса или прокрутки после того, как обновлённый DOM применён, через tick

Предварительные знания

  • Руна `$effect` и её функция очистки
  • Понимание разницы между серверным рендерингом и клиентом
  • JavaScript: таймеры, подписки и необходимость их снимать

onMount и onDestroy

Функция onMount из svelte принимает колбэк, который выполняется один раз после того, как компонент примонтирован в DOM на клиенте. Это правильное место для кода, которому нужен существующий узел: инициализация сторонней библиотеки, чтение размеров, запуск таймера. Функция onDestroy выполняет колбэк перед удалением компонента - там снимают подписки и останавливают таймеры.

onMount запускает интервал после монтирования, а onDestroy очищает его перед удалением компонента, чтобы таймер не продолжал тикать в пустоту. Удобное сокращение: если колбэк onMount возвращает функцию, Svelte вызовет её при удалении как очистку - тогда отдельный onDestroy не нужен.

onMount выполняется только в браузере и не вызывается при серверном рендеринге. Поэтому код, обращающийся к браузерным объектам вроде window или document, безопасно держать внутри onMount - на сервере он просто не запустится.

Когда выполняется колбэк, переданный в onMount?

Как `$effect` заменяет большинство хуков

В Svelte 4 для реакции на изменения данных были реактивные блоки и хуки вроде beforeUpdate и afterUpdate. В Svelte 5 их роль взяла руна `$effect`. Эффект автоматически перезапускается, когда меняется любое прочитанное в нём реактивное состояние, и может вернуть функцию очистки, которую Svelte вызовет перед следующим запуском и при удалении. Это покрывает большинство задач, ради которых раньше брали лайфсайкл-хуки.

Эффект читает userId, поэтому при его изменении запускается заново и перезапрашивает данные. Возвращённая функция отменяет предыдущий запрос через AbortController перед новым запуском - встроенная очистка вместо ручного отслеживания в afterUpdate. Логика реакции и очистки лежит в одном месте.

ЗадачаSvelte 4Svelte 5
Реакция на изменение данныхРеактивный блок`$effect`
Код перед обновлениемbeforeUpdate`$effect.pre`
Очистка при перезапускеРучное отслеживаниеВозврат функции из `$effect`
Код после монтированияonMountonMount или `$effect`

Не всё стоит переносить в `$effect`. Если значение просто вычисляется из других, это `$derived`, а не эффект. Эффект - для побочных действий: запросы, подписки, ручная работа с DOM. Вычисления через эффект усложняют граф зависимостей и ведут к лишним перезапускам.

Почему `$effect` заменяет большинство хуков жизненного цикла из Svelte 4?

tick и SSR-безопасный лайфсайкл

Svelte применяет изменения к DOM не мгновенно при смене состояния, а пакетом в следующий микротакт. Если после изменения состояния нужно поработать с уже обновлённым DOM - поставить фокус, измерить высоту, прокрутить к элементу - дожидаются обновления через функцию tick из svelte. Она возвращает промис, который разрешается, когда отложенные изменения применены к DOM.

После добавления элемента новый узел ещё не в DOM, поэтому прокрутка к низу сработала бы по старой высоте. await tick дожидается применения изменений, и только потом читается scrollHeight, уже включающий новый элемент. Без ожидания прокрутка отстала бы на один шаг.

В SvelteKit компоненты рендерятся и на сервере, поэтому лайфсайкл должен быть SSR-безопасным. onMount и эффекты на сервере не выполняются - это и делает их безопасным местом для браузерного кода. Прямое обращение к window или document вне этих точек упадёт при серверном рендеринге, потому что таких объектов на сервере нет.

Обращение к window, document или localStorage на верхнем уровне блока script выполнится и при SSR, где этих объектов нет, и вызовет ошибку. Браузерный код размещают внутри onMount или эффекта, которые на сервере не запускаются, либо проверяют среду выполнения перед обращением.

Зачем дожидаться tick после изменения состояния?

Связь с другими темами

Жизненный цикл тесно связан с эффектами и средой выполнения:

  • `$effect`: побочные эффекты — Эффект заменяет большинство задач лайфсайкла и сам очищает ресурсы
  • Actions — Action - локальный лайфсайкл одного DOM-узла с настройкой и очисткой
  • SvelteKit: маршрутизация — SSR делает важной безопасность лайфсайкла на сервере

Итог

  • onMount запускает функцию после первого монтирования компонента в DOM на клиенте
  • onDestroy выполняет код перед удалением компонента - место для снятия подписок
  • Руна `$effect` заменяет большинство задач лайфсайкла: реагирует на состояние и возвращает функцию очистки
  • tick возвращает промис, который разрешается после применения отложенных изменений к DOM
  • onMount не выполняется при SSR, поэтому браузерный код, например обращение к window, размещают именно там

Связанные уроки

  • sv-08-effect — `$effect` - основной инструмент реакции на изменения и часто заменяет хуки жизненного цикла
  • sv-15-actions — Action тоже работает с монтированием и очисткой узла, но локально для одного элемента
  • sv-18-routing — SSR-безопасный лайфсайкл важен в SvelteKit, где компоненты рендерятся и на сервере
Жизненный цикл: onMount и `$effect`

0

1

Войти