Управление lifecycle

Lifecycle в контексте анимаций — это полный цикл существования анимационного процесса: от инициализации до завершения или остановки. В библиотеке Popmotion lifecycle контролируется через объекты анимаций и механизмы подписки (start, stop, complete), позволяя точно управлять поведением во времени.

Каждая анимация в Popmotion представляет собой поток значений, который можно запускать, останавливать и отслеживать. Управление lifecycle критично при построении сложных интерфейсов, где требуется синхронизация, отмена или повторный запуск анимаций.


Запуск анимации: метод start

Любая анимация в Popmotion запускается с помощью метода start. Он принимает обработчик, который вызывается при каждом обновлении значения.

import { tween } from "popmotion";

const animation = tween({ from: 0, to: 100, duration: 1000 });

const controls = animation.start({
  update: v => console.log(v),
  complete: () => console.log("Завершено")
});

Ключевые особенности:

  • update вызывается на каждом кадре
  • complete вызывается при завершении анимации
  • start возвращает объект управления (controls)

Объект управления анимацией

Результат вызова start — это объект, который позволяет контролировать lifecycle:

controls.stop();

Основные методы:

  • stop() — принудительная остановка анимации
  • отсутствие автоматического перезапуска после остановки

Остановка анимации не вызывает complete, что важно учитывать при построении логики.


Завершение анимации: complete

Анимация считается завершённой, если она достигла своего конечного состояния без прерывания.

tween({ from: 0, to: 1 })
  .start({
    update: v => {},
    complete: () => console.log("Анимация завершена")
  });

Особенности:

  • вызывается только при естественном завершении
  • не вызывается при stop()
  • полезен для запуска последующих действий

Прерывание lifecycle

Прерывание — это остановка анимации до её завершения:

const controls = tween({ from: 0, to: 100 }).start({
  update: v => console.log(v)
});

setTimeout(() => {
  controls.stop();
}, 500);

Поведение:

  • анимация прекращается немедленно
  • текущее значение фиксируется
  • complete не вызывается

Это особенно важно при смене состояний интерфейса, когда старая анимация больше не актуальна.


Повторный запуск анимации

После остановки анимации её необходимо запускать заново:

const animation = tween({ from: 0, to: 100 });

let controls = animation.start({ update: v => console.log(v) });

// позже
controls.stop();

// новый запуск
controls = animation.start({ update: v => console.log(v) });

Каждый вызов start создаёт новый lifecycle.


Управление несколькими анимациями

Часто требуется координировать несколько анимаций. Для этого удобно хранить ссылки на их контроллеры:

const animations = [];

animations.push(
  tween({ from: 0, to: 100 }).start({ update: v => console.log(v) })
);

animations.push(
  tween({ from: 100, to: 0 }).start({ update: v => console.log(v) })
);

// остановка всех
animations.forEach(a => a.stop());

Композиция lifecycle

Popmotion предоставляет инструменты для объединения анимаций:

Параллельное выполнение: parallel

import { parallel, tween } from "popmotion";

parallel(
  tween({ from: 0, to: 100 }),
  tween({ from: 1, to: 0 })
).start({
  update: ([x, y]) => console.log(x, y),
  complete: () => console.log("Все завершены")
});

Lifecycle завершается, когда завершены все вложенные анимации.


Последовательное выполнение: chain

import { chain, tween } from "popmotion";

chain(
  tween({ from: 0, to: 100 }),
  tween({ from: 100, to: 200 })
).start({
  update: v => console.log(v),
  complete: () => console.log("Цепочка завершена")
});

Каждая следующая анимация запускается после завершения предыдущей.


Отслеживание состояния через value

Для более тонкого контроля lifecycle используется value:

import { value, tween } from "popmotion";

const val = value(0, v => console.log(v));

const controls = tween({ to: 100 }).start(val);

Преимущества:

  • централизованное хранение состояния
  • возможность подписки на изменения
  • повторное использование значения

Отписка от изменений

При работе с value можно управлять подписками:

const subscription = val.subscribe(v => console.log("Sub:", v));

// позже
subscription.unsubscribe();

Это позволяет контролировать lifecycle подписчиков отдельно от самой анимации.


Управление lifecycle в реактивных потоках

Popmotion поддерживает реактивный подход, где анимации можно комбинировать:

import { tween } from "popmotion";

const animation = tween({ from: 0, to: 100 });

const controls = animation.start({
  update: v => console.log(v)
});

// управление жизненным циклом
setTimeout(() => controls.stop(), 300);

Пауза и возобновление (через пользовательскую логику)

В Popmotion нет встроенного метода pause, но его можно реализовать:

let current = 0;
let controls;

function startAnimation(from) {
  controls = tween({ from, to: 100, duration: 1000 })
    .start({
      update: v => current = v
    });
}

startAnimation(0);

// пауза
setTimeout(() => {
  controls.stop();
}, 500);

// продолжение
setTimeout(() => {
  startAnimation(current);
}, 1000);

Очистка ресурсов

Важно освобождать ресурсы при завершении работы:

  • останавливать анимации (stop)
  • удалять подписки (unsubscribe)
  • не хранить устаревшие ссылки

Это предотвращает утечки памяти и лишние вычисления.


Типичные ошибки управления lifecycle

1. Отсутствие остановки Анимации продолжают работать даже когда компонент уничтожен.

2. Дублирование запусков Несколько start без остановки предыдущих анимаций.

3. Игнорирование complete Пропуск логики завершения цепочек.

4. Потеря ссылок на controls Невозможность остановить анимацию позже.


Практика: управление lifecycle в интерфейсе

let controls;

function open() {
  if (controls) controls.stop();

  controls = tween({ from: 0, to: 1 }).start({
    update: v => {
      document.body.style.opacity = v;
    }
  });
}

function close() {
  if (controls) controls.stop();

  controls = tween({ from: 1, to: 0 }).start({
    update: v => {
      document.body.style.opacity = v;
    }
  });
}

Здесь lifecycle каждой анимации контролируется явно, предотвращая конфликты.


Архитектурные подходы

Централизованный менеджер анимаций

  • хранение всех контроллеров
  • единая точка остановки

Инкапсуляция lifecycle

  • обёртки вокруг анимаций
  • управление внутри компонентов

Декларативный подход

  • описание состояний вместо ручного контроля

Глубокая интеграция lifecycle

При построении сложных систем lifecycle становится частью архитектуры:

  • синхронизация UI и анимаций
  • управление состояниями переходов
  • отмена устаревших действий

Popmotion предоставляет низкоуровневые инструменты, позволяя гибко выстраивать lifecycle под конкретные задачи.