Задать вопрос

Как лучше реализовать много анимаций в react?

привет! есть приложение на реакте и такая задача:
по определенному событию, из нижних левого и правого углов экрана должны вылетать дивы различной высоты и цвета, с различной скоростью и пропадать через 1-2 секунды. что-то вроде анимации "конфетти".

и вообще не представляю, как правильно это реализовать, не просев по производительности (может вылетать до 1000 дивов за раз). возможно, 5-10т "вылетевших" анимированных дивов и не является большой нагрузкой, но все же хочется сделать все по уму.

как я себе это представляю:
0. создаем css анимацию @keyframes pull { from, to }
1. создаем кнопку, при onClick на которую запускается наш хаос
2. маунтим в dom нужное количество div-ов, у которого в инлайн стилях width (рандом от 5 до 20px), height (=width, чтобы были квадраты), background (рандом из заранее составленного массива), transform rotate (рандом, чтобы квадраты летели не вертикально вверх), bottom (-width, чтобы вылетали снизу), left (рандом от 0% до 100% ширины экрана), animation-name (pull), animation-delay (рандом), animation-duration (рандом) etc.
3. по завершению анимации каждого дива, удаляем его из dom.

таким образом, решением будет что-то типа такого:
... JXS page
<div className="confettiLayer">{[...Array(1000)].map((_, index) => <ConfettiItem key={item} />)}</div>
...JXS page

... компонент ConfettiItem
const [ended, setEnded] = useState(false);

const duration = useMemo(() => getRandom(1000, 2000), []); // сколько сек (от 1 до 2) див будет вылетать, перед тем как изчезнет
const size = useMemo(() => getRandom(5, 20), []); // генерируем и мемоизируем width и height квадрата
const background = useMemo(() => getRandomFromArray(BACKGROUNDS), []); // случайный фон
const rotate = useMemo(() => getRandom(-340, 20), []); // рандомное значение для transform rotate
// остальные рандомные значения

useEffect(() => {
   const timer = setTimeout(() => {
          setEnded(true);
   }, duration);
      
   return () => {
       clearTimeout(timer);
   };
}[]);

// если !ended, то рендерим див, иначе не рендерим
return ended ? null : <div style={{ background, width: size, height: size, animationName: 'pull', animationDuration: `${duration}s` ...остальные стили с рандомными значениями}} />


в целом, выглядит адекватно, но меня очень смущает реализация. чем именно смущает понять не могу, но это джуновская реализация.

подскажите, как бы вы реализовали такую задачу? не прошу реализовывать с нуля, прошу людей с опытом лишь направить джуна на нужные материалы/либы/в нужную сторону.

может есть какой-нибудь паттерн для такой задачи? может нужно реализовать через создание специального класса в стиле ООП (ООП особо не придерживаюсь, тк пока еще не познал и не понял мощь этой парадигмы).
  • Вопрос задан
  • 292 просмотра
Подписаться 4 Сложный 4 комментария
Пригласить эксперта
Ответы на вопрос 2
@nokkc
Canvas обычно для такого рода анимаций используют, особенно если положения "частиц" зависят друг от друга и новые координаты нельзя высчитать за один проход массива с элементами
Как пример, можно посмотреть реализацию либы https://www.npmjs.com/package/react-confetti
Ответ написан
Комментировать
@kyzinatra
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы