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

Для использования ScrollMagic в React необходимо установить библиотеку через npm или yarn:

npm install scrollmagic

или

yarn add scrollmagic

Важным моментом является то, что ScrollMagic изначально ориентирован на работу с DOM напрямую. В React рекомендуется создавать экземпляры Controller и Scene только после того, как компоненты смонтированы, чтобы избежать ошибок доступа к DOM.

Пример подключения:

import React, { useEffect, useRef } from 'react';
import ScrollMagic from 'scrollmagic';

const ScrollComponent = () => {
  const triggerRef = useRef(null);

  useEffect(() => {
    const controller = new ScrollMagic.Controller();

    const scene = new ScrollMagic.Scene({
      triggerElement: triggerRef.current,
      duration: 300,
      triggerHook: 0.5
    })
    .setClassToggle(triggerRef.current, 'active')
    .addTo(controller);

    return () => {
      scene.destroy();
      controller.destroy();
    };
  }, []);

  return (
    <div ref={triggerRef} className="box">
      Контент для анимации
    </div>
  );
};

export default ScrollComponent;

Ключевые моменты:

  • useRef используется для прямого доступа к DOM-элементу, который будет триггером сцены.
  • useEffect обеспечивает создание и очистку сцены после монтирования компонента.
  • scene.destroy() и controller.destroy() обязательны для предотвращения утечек памяти.

Использование анимаций с GSAP

ScrollMagic тесно интегрируется с библиотекой анимаций GSAP. В React подход остаётся таким же — анимации создаются внутри useEffect после монтирования компонентов:

import React, { useEffect, useRef } from 'react';
import ScrollMagic from 'scrollmagic';
import { gsap } from 'gsap';
import 'animation.gsap';

const GsapScroll = () => {
  const boxRef = useRef(null);

  useEffect(() => {
    const controller = new ScrollMagic.Controller();

    const tween = gsap.to(boxRef.current, {
      x: 500,
      rotation: 360,
      duration: 2
    });

    const scene = new ScrollMagic.Scene({
      triggerElement: boxRef.current,
      duration: 400
    })
    .setTween(tween)
    .addTo(controller);

    return () => {
      scene.destroy();
      controller.destroy();
    };
  }, []);

  return <div ref={boxRef} className="animated-box">Анимация GSAP</div>;
};

export default GsapScroll;

Важные аспекты:

  • setTween() позволяет привязать GSAP-анимацию к прокрутке.
  • duration сцены определяет длину анимации по прокрутке.
  • Любые анимации необходимо уничтожать вместе со сценой при размонтировании.

Работа с несколькими сценами

Для сложных интерфейсов часто создаются несколько сцен в одном компоненте. На практике рекомендуется использовать один Controller на компонент и несколько сцен, чтобы экономить ресурсы:

const MultiScene = () => {
  const ref1 = useRef(null);
  const ref2 = useRef(null);

  useEffect(() => {
    const controller = new ScrollMagic.Controller();

    const scene1 = new ScrollMagic.Scene({
      triggerElement: ref1.current,
      duration: 200
    })
    .setClassToggle(ref1.current, 'visible')
    .addTo(controller);

    const scene2 = new ScrollMagic.Scene({
      triggerElement: ref2.current,
      duration: 300
    })
    .setClassToggle(ref2.current, 'visible')
    .addTo(controller);

    return () => {
      scene1.destroy();
      scene2.destroy();
      controller.destroy();
    };
  }, []);

  return (
    <>
      <div ref={ref1} className="box">Первая сцена</div>
      <div ref={ref2} className="box">Вторая сцена</div>
    </>
  );
};

Рекомендации при работе с несколькими сценами:

  • Один Controller на компонент уменьшает нагрузку на рендеринг.
  • Для динамически создаваемых элементов можно использовать массив refs и map() для генерации сцен.
  • Обязательно очищать все сцены в useEffect при размонтировании.

Контроль с прокруткой и триггерами

triggerHook позволяет управлять моментом срабатывания сцены:

  • 0 — верх окна браузера
  • 0.5 — середина окна
  • 1 — низ окна

duration задаёт длину сцены. Для полной анимации, которая должна совпадать с прокруткой страницы, можно использовать % или пиксели.

const scene = new ScrollMagic.Scene({
  triggerElement: ref.current,
  triggerHook: 0.5,
  duration: window.innerHeight
})
.setClassToggle(ref.current, 'active')
.addTo(controller);

Советы:

  • Для адаптивных интерфейсов duration лучше вычислять динамически, основываясь на высоте окна или элемента.
  • При использовании setPin() элемент фиксируется на время сцены, что позволяет создавать эффект параллакса или «липких» секций.

Интеграция с React Router

ScrollMagic не взаимодействует напрямую с React Router, но при смене маршрутов необходимо очищать все сцены, чтобы предотвратить конфликты:

import { useLocation } from 'react-router-dom';

useEffect(() => {
  const controller = new ScrollMagic.Controller();
  
  // Создание сцен...

  return () => {
    controller.destroy();
  };
}, [useLocation()]);

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


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

  • Минимизировать количество одновременно активных сцен.
  • Использовать addIndicators() только для разработки.
  • Создавать сцены после полной загрузки контента, чтобы избежать некорректного расчёта высот.
  • Удалять все сцены и контроллеры при размонтировании компонентов.

Эти принципы позволяют использовать ScrollMagic в React максимально эффективно, сохраняя производительность и стабильность приложения.