Использование библиотеки anime.js в React требует учета особенностей жизненного цикла компонентов и принципов декларативного подхода. Основная задача — корректно управлять анимациями, избегая конфликтов с механизмом рендеринга React.
Установка выполняется через пакетный менеджер:
npm install animejs
Импорт в компоненте:
import anime from 'animejs';
React не предоставляет прямого доступа к DOM-элементам, поэтому для
анимаций используется useRef.
import { useEffect, useRef } from 'react';
import anime from 'animejs';
function Box() {
const boxRef = useRef(null);
useEffect(() => {
anime({
targets: boxRef.current,
translateX: 250,
duration: 1000
});
}, []);
return <div ref={boxRef} className="box" />;
}
Ключевые моменты:
useRef хранит ссылку на DOM-элементuseEffect гарантирует запуск анимации после
монтированияtargets принимает boxRef.currentАнимации необходимо очищать при размонтировании компонента, чтобы избежать утечек памяти.
useEffect(() => {
const animation = anime({
targets: boxRef.current,
translateX: 250,
duration: 1000
});
return () => {
animation.pause();
};
}, []);
Анимации могут зависеть от состояния (useState).
import { useState, useEffect, useRef } from 'react';
import anime from 'animejs';
function ToggleBox() {
const [active, setActive] = useState(false);
const ref = useRef(null);
useEffect(() => {
anime({
targets: ref.current,
translateX: active ? 200 : 0,
duration: 500,
easing: 'easeInOutQuad'
});
}, [active]);
return (
<div>
<div ref={ref} className="box" />
<button onCl ick={() => setActive(!active)}>Toggle</button>
</div>
);
}
Особенность: React управляет состоянием, а anime.js — визуальным представлением.
Для анимации списка элементов используется ref с
массивом или селектор.
const refs = useRef([]);
useEffect(() => {
anime({
targets: refs.current,
translateY: [50, 0],
opacity: [0, 1],
delay: anime.stagger(100)
});
}, []);
return items.map((item, i) => (
<div
key={i}
ref={el => refs.current[i] = el}
className="item"
>
{item}
</div>
));
Для сложных последовательностей удобно использовать таймлайны.
useEffect(() => {
const tl = anime.timeline({
easing: 'easeOutExpo',
duration: 750
});
tl.add({
targets: '.box',
translateX: 250
}).add({
targets: '.box',
translateY: 100
}).add({
targets: '.box',
rotate: 360
});
}, []);
Преимущества:
При использовании CSS-модулей:
import styles from './Box.module.css';
<div ref={ref} className={styles.box} />
Для anime.js важно передавать сам DOM-элемент, а не имя класса.
React не имеет встроенной поддержки анимации удаления элементов, поэтому требуется ручное управление.
function FadeComponent({ visible }) {
const ref = useRef(null);
useEffect(() => {
if (visible) {
anime({
targets: ref.current,
opacity: [0, 1],
duration: 500
});
} else {
anime({
targets: ref.current,
opacity: [1, 0],
duration: 500
});
}
}, [visible]);
return visible ? <div ref={ref}>Content</div> : null;
}
Рекомендации:
transform вместо изменения
layout-свойствПример оптимизации:
anime({
targets: element,
translateX: 100, // вместо left
willChange: 'transform'
});
Анимации можно запускать в ответ на пользовательские действия.
const handleClick = () => {
anime({
targets: ref.current,
scale: 1.5,
duration: 300
});
};
<button onCl ick={handleClick}>Click</button>
Создание собственного хука упрощает работу:
import { useEffect } from 'react';
import anime from 'animejs';
export function useAnime(ref, params, deps = []) {
useEffect(() => {
const animation = anime({
targets: ref.current,
...params
});
return () => animation.pause();
}, deps);
}
Использование:
useAnime(ref, {
translateX: 200,
duration: 1000
}, []);
anime.js отлично подходит для анимации SVG внутри React.
useEffect(() => {
anime({
targets: 'path',
strokeDashoffset: [anime.setDashoffset, 0],
duration: 2000,
easing: 'easeInOutSine'
});
}, []);
Для сложных интерфейсов полезно хранить ссылки на анимации:
const animations = useRef([]);
useEffect(() => {
animations.current.push(
anime({ targets: ref.current, translateX: 100 })
);
return () => {
animations.current.forEach(anim => anim.pause());
};
}, []);
anime.js поддерживает промисы:
useEffect(() => {
async function run() {
await anime({
targets: ref.current,
translateX: 200,
duration: 1000
}).finished;
console.log('Animation complete');
}
run();
}, []);
1. Использование селекторов вместо ref React может перерисовать DOM, и селекторы перестанут работать корректно.
2. Запуск анимации до монтирования Решается
использованием useEffect.
3. Отсутствие очистки Приводит к утечкам памяти и багам.
4. Конфликт с React Strict Mode В режиме разработки
useEffect может вызываться дважды.
anime.js можно использовать вместе с:
Однако важно избегать одновременного управления одним и тем же DOM-элементом разными библиотеками.
Подход 1: Локальные анимации внутри компонентов
Подход 2: Централизованное управление
Подход 3: Хуки и абстракции
import { useEffect, useRef } from 'react';
import anime from 'animejs';
function AnimatedCard() {
const ref = useRef(null);
useEffect(() => {
const animation = anime({
targets: ref.current,
opacity: [0, 1],
translateY: [50, 0],
duration: 800,
easing: 'easeOutQuad'
});
return () => animation.pause();
}, []);
return (
<div ref={ref} className="card">
Card Content
</div>
);
}
useEffectГлубокая интеграция anime.js в React достигается через аккуратное
управление жизненным циклом, изоляцию DOM-доступа через ref
и построение переиспользуемых абстракций.