Подходы для других фреймворков

Базовый механизм работы Lottie Web опирается на явную инициализацию анимации через функцию lottie.loadAnimation, которой передаётся контейнер DOM-элемента и конфигурация анимации. Во всех фреймворках различия сводятся к моменту появления DOM-узла и управлению жизненным циклом компонента.

Ключевые требования при интеграции:

  • наличие готового DOM-контейнера
  • корректное уничтожение инстанса анимации
  • контроль повторной инициализации при изменении props/state
  • защита от SSR-окружений, где отсутствует window

React: управление через refs и эффекты жизненного цикла

В React интеграция строится вокруг useRef и useEffect, где контейнер создаётся декларативно, а Lottie инициализируется императивно.

Базовый паттерн

import { useEffect, useRef } from "react";
import lottie from "lottie-web";

function LottiePlayer({ animationData, loop = true, autoplay = true }) {
  const containerRef = useRef(null);
  const animationInstance = useRef(null);

  useEffect(() => {
    if (!containerRef.current) return;

    animationInstance.current = lottie.loadAnimation({
      container: containerRef.current,
      renderer: "svg",
      loop,
      autoplay,
      animationData,
    });

    return () => {
      animationInstance.current?.destroy();
    };
  }, [animationData, loop, autoplay]);

  return <div ref={containerRef} />;
}

Управление обновлением анимации

При смене animationData важно уничтожать предыдущий инстанс до создания нового. Иначе возникает наложение SVG слоёв и утечки памяти.

SSR-ограничения

В Next.js и аналогичных окружениях требуется защита:

if (typeof window === "undefined") return null;

или динамический импорт:

import dynamic from "next/dynamic";

const LottiePlayer = dynamic(() => import("./LottiePlayer"), {
  ssr: false,
});

Оптимизация повторных рендеров

Использование useMemo для стабилизации animationData и useRef для хранения инстанса предотвращает лишние пересоздания.


Vue 3: директивы и Composition API

Vue предоставляет несколько уровней интеграции: компонентный и директивный.

Composition API подход

import { ref, onMounted, onBeforeUnmount, watch } from "vue";
import lottie from "lottie-web";

export default {
  props: {
    animationData: Object,
    loop: Boolean,
    autoplay: Boolean,
  },
  setup(props) {
    const container = ref(null);
    let animation = null;

    const init = () => {
      if (!container.value) return;

      animation = lottie.loadAnimation({
        container: container.value,
        renderer: "svg",
        loop: props.loop,
        autoplay: props.autoplay,
        animationData: props.animationData,
      });
    };

    onMounted(init);

    watch(() => props.animationData, () => {
      animation?.destroy();
      init();
    });

    onBeforeUnmount(() => {
      animation?.destroy();
    });

    return { container };
  },
};

Директива v-lottie

Директивный подход удобен для повторного использования:

  • mounted — инициализация
  • updated — пересоздание при изменениях
  • unmounted — очистка

Преимущество директив — минимальная связность с компонентной логикой.


Angular: компонентная инкапсуляция и lifecycle hooks

Angular требует строгого управления жизненным циклом через хуки.

Базовая реализация компонента

import { Component, ElementRef, Input, AfterViewInit, OnDestroy, ViewChild } from "@angular/core";
import lottie from "lottie-web";

@Component({
  selector: "app-lottie",
  template: `<div #container></div>`,
})
export class LottieComponent implements AfterViewInit, OnDestroy {
  @ViewChild("container", { static: true }) container!: ElementRef;
  @Input() animationData: any;
  @Input() loop = true;
  @Input() autoplay = true;

  private animation: any;

  ngAfterViewInit() {
    this.initAnimation();
  }

  ngOnDestroy() {
    this.animation?.destroy();
  }

  private initAnimation() {
    this.animation = lottie.loadAnimation({
      container: this.container.nativeElement,
      renderer: "svg",
      loop: this.loop,
      autoplay: this.autoplay,
      animationData: this.animationData,
    });
  }
}

Обновление через ngOnChanges

При изменении входных параметров требуется пересоздание:

ngOnChanges() {
  this.animation?.destroy();
  this.initAnimation();
}

Особенности Angular Zone

Lottie работает вне Angular Zone, поэтому при необходимости синхронизации UI используется NgZone.runOutsideAngular.


Svelte: actions как минимальный слой абстракции

Svelte позволяет интегрировать Lottie через actions — компактный механизм привязки поведения к DOM.

Action-подход

import lottie from "lottie-web";

export function lottieAction(node, params) {
  let animation;

  function init() {
    animation = lottie.loadAnimation({
      container: node,
      renderer: "svg",
      loop: params.loop,
      autoplay: params.autoplay,
      animationData: params.animationData,
    });
  }

  init();

  return {
    update(newParams) {
      animation?.destroy();
      params = newParams;
      init();
    },
    destroy() {
      animation?.destroy();
    },
  };
}

Использование

<div use:lottieAction="{animationConfig}" />

Svelte минимизирует boilerplate, оставляя только управление жизненным циклом.


Next.js и Nuxt: особенности SSR и гидратации

При использовании серверного рендеринга ключевая проблема — отсутствие DOM и window.

Основные стратегии

  • отключение SSR для компонента
  • динамическая загрузка
  • проверка окружения

Client-only компонент

if (typeof window !== "undefined") {
  lottie.loadAnimation(...);
}

Next.js dynamic import

import dynamic from "next/dynamic";

const Lottie = dynamic(() => import("./Lottie"), { ssr: false });

Nuxt client-only

<ClientOnly>
  <Lottie />
</ClientOnly>

Унифицированный wrapper-компонент

Во всех фреймворках повторяется одинаковая структура:

  • контейнер DOM
  • инициализация Lottie
  • destroy при unmount
  • реакция на изменения конфигурации

Абстракция обычно включает:

  • containerRef
  • animationInstance
  • init()
  • destroy()
  • update()

Управление состоянием анимации через внешний API

Lottie instance предоставляет методы:

  • play()
  • pause()
  • stop()
  • setSpeed(value)
  • goToAndPlay(frame)
  • goToAndStop(frame)

Во фреймворках эти методы проксируются через ref или emits.

React пример управления

animationInstance.current?.setSpeed(1.5);

Vue пример

this.animation?.pause();

Типичные ошибки интеграции

Утечки памяти

Возникают при отсутствии destroy() при размонтировании компонента.

Повторная инициализация без очистки

Приводит к наложению SVG элементов и дублированию DOM.

Несоответствие размеров контейнера

Lottie рассчитывает canvas/svg исходя из размеров родителя, поэтому динамическое изменение размеров требует пересчёта или resize().

Несинхронное обновление данных

Смена animationData без пересоздания instance приводит к некорректному состоянию.


Производительность и оптимизация

Минимизация пересозданий

  • стабилизация props
  • мемоизация конфигурации
  • разделение UI и анимации

Управление рендерингом

SVG-рендеринг более гибкий, но тяжелее при сложных сценах. Canvas обеспечивает стабильную производительность при большом количестве элементов.

Отложенная инициализация

Lazy mount снижает нагрузку при загрузке страницы:

  • IntersectionObserver
  • viewport-based initialization

Выбор renderer: SVG и Canvas

Lottie Web поддерживает несколько рендереров:

  • SVG — лучше для интерактивности и масштабирования
  • Canvas — лучше для сложных анимаций и высокой частоты кадров
  • HTML — редко используется, ограниченная поддержка

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