React хуки: кастомный useFlyMotion для анимаций как в Fly
-
Кастомный хук useFlyMotion упрощает создание плавных анимаций в React, вдохновлённых стилем Fly-приложения. Он использует react-spring для реалистичных переходов элементов, таких как списки или модалки. Это решает проблему сложных настроек анимаций вручную.
С ним вы быстро добавите fly-подобные эффекты — лёгкие появления, исчезновения и перемещения. Подходит для списков задач, карточек или уведомлений. Давайте разберём, как это работает на примерах.
Что такое useFlyMotion и зачем он нужен
Кастомный хук useFlyMotion — это обёртка над хуками react-spring, которая имитирует фирменные анимации Fly: быстрый старт, плавный полёт и мягкую остановку. Представьте список сообщений, где новые элементы “влетают” слева или сверху, а старые выезжают вправо. Без такого хука приходится комбинировать useSpring, useTransition и useChain вручную — это часы кода.
В реальных проектах это упрощает анимацию списков и модальных окон. Например, в таск-менеджере карточки задач плавно сдвигаются при добавлении новой. Хук берёт на себя расчёт траекторий, скорости и callbacks, оставляя вам только данные. Логично перейти к примерам: вот как он решает типичные задачи.
- Плавное появление элементов: Хук автоматически анимирует opacity и transform для входа.
- Сдвиги по осям: Поддержка направлений (слева, справа, сверху) через config.
- Синхронизация анимаций: Встроенный useChain для цепочек эффектов.
Параметр Описание Пример elements Массив элементов для анимации [{id: 1, content: 'Задача'}]direction Направление полёта 'left','right','up'reset Сброс анимации при повторном запуске trueКак реализовать базовый useFlyMotion
Реализация начинается с импорта хуков из react-spring. Хук принимает элементы, уникальные ключи и объект конфигурации для анимации. Внутри мы используем useTransition для монтирования/размонтирования, а useSpring — для базовых свойств вроде позиции и прозрачности. Это даёт эффект “полёта”: элементы стартуют с отрицательного translateX/Y и плавно прилетают.
Пример: список уведомлений, где новое сообщение влетает справа. Хук возвращает массив анимированных стилей, готовых к применению в map(). Без него пришлось бы писать отдельные анимации для enter/exit. Теперь посмотрим код шаг за шагом.
import { useTransition, animated, config } from '@react-spring/web'; function useFlyMotion(elements, direction = 'left', reset = true) { return useTransition(elements, { keys: item => item.id, from: getFromStyles(direction), enter: getEnterStyles(direction), leave: { opacity: 0, transform: 'translateX(100%)' }, config: config.gentle, reset, }); } function getFromStyles(dir) { switch (dir) { case 'right': return { opacity: 0, transform: 'translateX(100%)' }; case 'up': return { opacity: 0, transform: 'translateY(-100%)' }; default: return { opacity: 0, transform: 'translateX(-100%)' }; } } function getEnterStyles(dir) { return { opacity: 1, transform: 'translateX(0%)' }; }- from/enter/leave: Определяют старт, цель и выход анимации.
- config.gentle: Делает движение пружинистым, как в Fly.*
- keys: Уникальные ID для отслеживания изменений.*
Пример использования в списке карточек
Теперь применим хук к списку задач. Компонент хранит массив объектов с id и текстом. При добавлении новой задачи старые сдвигаются, а новая влетает. useFlyMotion берёт state напрямую, возвращая transitions — массив с style и item. В рендере маппим их на animated.div.
Это решает проблему лагающих списков при частых обновлениях. React-spring оптимизирует FPS, а хук добавляет визуальный polish. Вот полный компонент:
import { useState } from 'react'; import { useFlyMotion } from './useFlyMotion'; function TaskList() { const [tasks, setTasks] = useState([ { id: 1, text: 'Сделать кофе' }, { id: 2, text: 'Проверить почту' }, ]); const transitions = useFlyMotion(tasks, 'right'); const addTask = () => { setTasks([...tasks, { id: Date.now(), text: `Задача ${tasks.length + 1}` }]); }; return ( <div> <button onClick={addTask}>Добавить задачу</button> {transitions((style, item) => ( <animated.div style={style} className="task-card"> {item.text} </animated.div> ))} </div> ); }Сценарий Эффект Преимущество Добавление Влет справа Плавный shift без рывков Удаление Вылет слева Не блокирует UI Множество Цепочка анимаций useChain внутри Ключевой нюанс: Всегда используйте уникальные id — иначе анимации сломаются при реордеринге.*
Расширения хука для продвинутых эффектов
Базовый хук легко доработать под FLIP-технику (First, Last, Invert, Play). Добавьте callback onRest для логики после анимации. Или интегрируйте useSpring для отдельных свойств, как scale или rotate. Например, для модалки: комбинируйте с backdrop-анимацией через useChain.
В сложных случаях хук принимает config как проп: { tension: 170, friction: 26 }. Это копирует физику Fly. Аргумент reset=true сбрасывает анимацию при каждом обновлении — идеально для динамических списков. Логично разобрать варианты кастомизации.
- Интеграция useChain: Цепочка для фона + контента модалки.
- Направления полёта: ‘left’, ‘right’, ‘up’, ‘down’ с разными from/enter.
- Callbacks: onStart/onRest для side-effects, как фокус после анимации.*
Хук Когда использовать Пример в FlyMotion useSpring Один элемент Scale карточки useTransition Списки Монтирование задач useChain Последовательность Backdrop затем контент Дальше за пределами базового хука
useFlyMotion покрывает 80% анимаций в стиле Fly, но для gesture-based эффектов (drag-to-dismiss) смотрите Framer Motion. Или комбинируйте с useGesture из react-spring. Осталось поэкспериментировать с physics: меняйте tension/friction под бренд.
Другие идеи — анимация роутинга с page transitions или infinite scroll с fade-in. Всё это строится на том же принципе, но требует тюнинга config под производительность.
© 2024 - 2025 ExLends, Inc. Все права защищены.