Подключение и базовая интеграция Lottie Web в React чаще всего строится вокруг императивного управления анимацией через DOM-узел, поскольку библиотека работает напрямую с canvas или SVG и не является React-ориентированной по архитектуре.
Основная идея интеграции заключается в том, что React отвечает за
жизненный цикл компонента, а Lottie Web — за управление анимацией внутри
конкретного DOM-контейнера. Это требует аккуратного связывания
useEffect, useRef и методов управления
анимацией.
Lottie использует JSON-файлы, экспортированные из After Effects через Bodymovin. Этот JSON содержит описание слоёв, ключевых кадров, интерполяций и векторных данных.
Типичная структура подключения в React начинается с установки пакета:
npm install lottie-web
В большинстве случаев JSON импортируется напрямую или загружается по URL:
import animationData from './animation.json';
или
const animationPath = '/animations/loader.json';
Связка React и Lottie Web строится через useRef, который
указывает на контейнер, где будет рендериться анимация.
import { useEffect, useRef } from 'react';
import lottie from 'lottie-web';
import animationData from './animation.json';
const LottieAnimation = () => {
const containerRef = useRef(null);
useEffect(() => {
const animation = lottie.loadAnimation({
container: containerRef.current,
renderer: 'svg',
loop: true,
autoplay: true,
animationData
});
return () => animation.destroy();
}, []);
return <div ref={containerRef} />;
};
Ключевой момент — обязательное уничтожение анимации при размонтировании компонента, иначе возникают утечки памяти и дублирование canvas-слоёв.
Lottie Web предоставляет объект анимации, который позволяет управлять воспроизведением:
play()pause()stop()setSpeed()goToAndPlay()goToAndStop()В React это обычно связывается с useRef, чтобы сохранить
экземпляр:
const animationRef = useRef(null);
useEffect(() => {
animationRef.current = lottie.loadAnimation({
container: containerRef.current,
renderer: 'svg',
loop: false,
autoplay: false,
animationData
});
return () => animationRef.current.destroy();
}, []);
Пример управления извне:
const play = () => {
animationRef.current.play();
};
const pause = () => {
animationRef.current.pause();
};
Часто требуется управлять состоянием анимации через свойства компонента: скорость, автозапуск, цикл.
const LottieAnimation = ({ speed = 1, isPlaying }) => {
const containerRef = useRef(null);
const animRef = useRef(null);
useEffect(() => {
animRef.current = lottie.loadAnimation({
container: containerRef.current,
renderer: 'svg',
loop: true,
autoplay: false,
animationData
});
return () => animRef.current.destroy();
}, []);
useEffect(() => {
if (!animRef.current) return;
animRef.current.setSpeed(speed);
}, [speed]);
useEffect(() => {
if (!animRef.current) return;
isPlaying ? animRef.current.play() : animRef.current.pause();
}, [isPlaying]);
return <div ref={containerRef} />;
};
Такой подход разделяет инициализацию и управление состоянием, предотвращая повторную загрузку анимации.
Lottie Web поддерживает несколько режимов рендеринга:
svg — наиболее распространённый вариантcanvas — лучше для сложных сцен и
производительностиhtml — используется редко, в специфических случаяхlottie.loadAnimation({
container: containerRef.current,
renderer: 'canvas',
loop: true,
autoplay: true,
animationData
});
SVG обеспечивает высокое качество и возможность стилизации через CSS, но может быть тяжелее при большом количестве элементов.
Canvas предпочтителен для больших анимаций с высокой частотой кадров.
В реальных приложениях анимации часто загружаются асинхронно:
useEffect(() => {
let anim;
fetch('/animations/data.json')
.then(res => res.json())
.then(data => {
anim = lottie.loadAnimation({
container: containerRef.current,
renderer: 'svg',
loop: true,
autoplay: true,
animationData: data
});
});
return () => {
if (anim) anim.destroy();
};
}, []);
Этот подход важен при использовании CDN или CMS, где JSON обновляется независимо от сборки фронтенда.
При использовании серверного рендеринга возникает проблема отсутствия
window и DOM. Поэтому загрузка Lottie Web должна
происходить только на клиенте.
import dynamic from 'next/dynamic';
const LottieAnimation = dynamic(() => import('./LottieAnimation'), {
ssr: false
});
Дополнительно внутри компонента проверяется наличие DOM:
useEffect(() => {
if (typeof window === 'undefined') return;
const anim = lottie.loadAnimation({
container: containerRef.current,
renderer: 'svg',
loop: true,
autoplay: true,
animationData
});
return () => anim.destroy();
}, []);
Lottie позволяет проигрывать части анимации, что полезно для интерактивных интерфейсов.
animRef.current.playSegments([0, 50], true);
Сегменты часто используются для:
Производительность напрямую зависит от размера JSON. В больших интерфейсах применяется предзагрузка:
const animationCache = {};
const loadAnimationData = async (url) => {
if (animationCache[url]) return animationCache[url];
const data = await fetch(url).then(r => r.json());
animationCache[url] = data;
return data;
};
Дополнительно используется:
SVG позволяет влиять на элементы через CSS:
svg path {
stroke: #4f46e5;
stroke-width: 2px;
}
Однако структура SVG генерируется динамически, поэтому селекторы должны быть достаточно общими или применяться через обёртки.
Lottie часто синхронизируется с UI-состоянием:
useEffect(() => {
if (!animRef.current) return;
if (status === 'loading') {
animRef.current.play();
} else if (status === 'done') {
animRef.current.stop();
}
}, [status]);
Такой подход делает анимации частью бизнес-логики интерфейса, а не декоративным элементом.
При частых перерендерах важно избегать повторного создания анимации. Используется проверка существования экземпляра:
if (animRef.current) {
animRef.current.destroy();
}
Также применяется useMemo для стабильности
конфигурации:
const options = useMemo(() => ({
renderer: 'svg',
loop: true,
autoplay: true,
animationData
}), []);
Для сложных интерфейсов используется ограничение FPS:
lottie.setQuality('low');
или динамическое переключение качества в зависимости от устройства.
На мобильных устройствах предпочтительнее canvas-рендеринг с пониженной детализацией, чтобы избежать просадок кадров.
В TypeScript проектах описывается тип анимации:
import { AnimationItem } from 'lottie-web';
const animRef = useRef<AnimationItem | null>(null);
Это позволяет безопасно управлять методами анимации и предотвращает
обращения к undefined.
Для масштабируемых систем создаются обёртки:
LottieuseLottieХук может выглядеть следующим образом:
const useLottie = (animationData) => {
const containerRef = useRef(null);
const animRef = useRef(null);
useEffect(() => {
animRef.current = lottie.loadAnimation({
container: containerRef.current,
renderer: 'svg',
loop: true,
autoplay: true,
animationData
});
return () => animRef.current.destroy();
}, [animationData]);
return { containerRef, animRef };
};
Такой слой абстракции упрощает интеграцию в дизайн-системы и крупные React-приложения.