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

Использование библиотеки anime.js в React требует учета особенностей жизненного цикла компонентов и принципов декларативного подхода. Основная задача — корректно управлять анимациями, избегая конфликтов с механизмом рендеринга React.


Установка и базовая настройка

Установка выполняется через пакетный менеджер:

npm install animejs

Импорт в компоненте:

import anime from 'animejs';

Работа с useRef для доступа к DOM

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>
));

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

Для сложных последовательностей удобно использовать таймлайны.

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-модулями и styled-components

При использовании 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;
}

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

Рекомендации:

  • избегать частых перезапусков анимаций
  • минимизировать количество DOM-операций
  • использовать 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
}, []);

Работа с SVG

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 можно использовать вместе с:

  • React Transition Group
  • Framer Motion (для сложных сценариев)
  • GSAP (в отдельных частях приложения)

Однако важно избегать одновременного управления одним и тем же 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>
  );
}

Особенности работы с React 18+

  • двойной вызов эффектов в Strict Mode
  • необходимость учитывать concurrent rendering
  • избегание побочных эффектов вне useEffect

Глубокая интеграция anime.js в React достигается через аккуратное управление жизненным циклом, изоляцию DOM-доступа через ref и построение переиспользуемых абстракций.