Анимируем компонент React при входе и выходе экрана

Введение
Анимация компонента при его появлении или удалении из DOM в React — типичная задача, которая часто путает. По умолчанию при скрытии React удаляет элемент из DOM, и у него нет времени проиграть анимацию выхода. Когда компонент возвращается, он мгновенно рендерится, что выглядит резким.
Framer Motion решает эту проблему: он предоставляет обёртки и API для анимации при добавлении и удалении элементов, управления переходами и уважения настроек доступности.
Что такое Framer Motion?
Framer Motion — производственная библиотека анимаций для React. Кратко: это набор компонентов и хуков для декларативной анимации элементов, включая ключевые кадры, кривые ускорения и управление временем. Определение терминов в одну строку:
- motion — компонент-обёртка для анимируемых элементов.
- AnimatePresence — компонент, который позволяет проигрывать exit-анимации перед удалением из DOM.
Преимущества: меньше ручного JS-кода, предсказуемые переходы и интеграция с жестами и событиями.
Когда Framer Motion не нужен
- Простые hover/active переходы — достаточно CSS-переходов.
- Если приложение строго SSR и вы не хотите увеличивать бандл — можно обойтись CSS или минимальными JS-решениями.
Important: всегда учитывайте prefers-reduced-motion для пользователей с потребностью в уменьшенной анимации.
Быстрый старт: создание проекта React
Если у вас ещё нет проекта, создайте его с помощью Vite. Пример с yarn:
yarn create vite my-app --template react
cd my-app
yarn
yarn devС npm:
npm create vite@latest my-app -- --template react
cd my-app
npm install
npm run devУстановка Framer Motion
Установите Framer Motion в проект:
npm install framer-motion
# или
yarn add framer-motionПростая анимация при входе и выходе
Основная идея: обёрнуть элемент в motion, а для выхода использовать AnimatePresence. Пример простого уведомления с кнопкой, которая показывает и скрывает компонент.
import { AnimatePresence, motion, useReducedMotion } from 'framer-motion'
import { useState } from 'react'
function App() {
const [isVisible, setIsVisible] = useState(true)
const shouldReduceMotion = useReducedMotion()
return (
<>
{isVisible && (
Sent!
)}
>
)
}
export default AppПояснения:
- initial — стартовое состояние перед анимацией входа.
- animate — целевое состояние после входа.
- exit — состояние для анимации выхода.
- AnimatePresence задерживает удаление элемента из DOM до тех пор, пока exit-анимация не завершится.
- useReducedMotion — хук для уважения системных настроек «уменьшить анимацию».
Добавление easing и настройки переходов
Кривые ускорения делают движение естественнее. В transition можно указать duration и ease. Пример с easeInOut:
Sent!
Если нужно более тонкое управление, можно задать разные transition для разных свойств:
animate={{
x: 0,
opacity: 1,
transition: {
x: { type: 'spring', stiffness: 300, damping: 30 },
opacity: { duration: 0.3 }
}
}}Практические советы и шаблоны
- Всегда задавайте уникальный key для списка элементов, чтобы AnimatePresence корректно определял элементы для exit-анимаций.
- Для последовательной замены элементов используйте AnimatePresence mode=’wait’ или в старых версиях exitBeforeEnter.
- Для сложных последовательностей используйте sequence API или контролируйте состояние анимации через onAnimationComplete.
- При анимации высоты используйте auto-animate при помощи layout или библиотек, либо плавно изменяйте maxHeight с overflow.
Дизайн и доступность
- Уважайте prefers-reduced-motion: отключайте или минимизируйте длительность анимаций.
- Не используйте яркую мерцающую анимацию — она может вызвать дискомфорт.
- Согласуйте анимации с дизайнером: длительности 150–500 мс обычно подходят для UI-переходов.
Критерии приёмки
- Компонент плавно входит и выходит при переключении состояния через кнопку.
- При включённом prefers-reduced-motion анимация либо сокращается, либо отсутствует.
- При быстрой многократной смене состояния не возникает визуальных артефактов.
- Для списков при удалении элемента он проигрывает exit-анимацию, не убираясь мгновенно.
Тест-кейсы / Acceptance criteria
- Нажать кнопку «Notify»: элемент появляется слева и принадлежит opacity 1 спустя 0.5 с.
- Нажать снова быстро: элемент проигрывает exit-анимацию и после этого снова появляется корректно.
- Проверить в настройках ОС «уменьшить движения»: анимация должна быть сведена к минимуму.
- Для списочного компонента с 3 элементами удалить второй — оставшиеся элементы должны сместиться корректно без мерцания.
Когда Framer Motion не подходит: контрпримеры
- Строго серверный рендеринг без гидратации: exit-анимации не работают до гидратации клиента.
- Очень простые эффекты hover — использование фреймворка добавит лишний вес бандла.
- Проекты с жёсткими ограничениями по размерам бандла могут предпочесть CSS или внутренние анимации.
Альтернативные подходы
- CSS-переходы и ключевые кадры для hover и простых появлений.
- react-transition-group — более лёгкая альтернатива для базовых входов/выходов.
- GreenSock (GSAP) для сложных временных линий и высокопроизводительных анимаций.
Мини-методология внедрения анимаций (шаги)
- Дизайн: прототип в Figma/Sketch — определите длительность и easing.
- Прототипирование: реализуйте анимацию в Storybook с отключённым motion для QA.
- Интеграция: добавьте Framer Motion, реализуйте initial/animate/exit и test cases.
- Тестирование: проверка accessibility, производительности, кроссбраузерности.
- Ревью: дизайнер подтверждает совпадение с макетом.
Checklist для ролей
Frontend-разработчик:
- Реализовал initial/animate/exit
- Добавил keys для списка
- Уважает prefers-reduced-motion
- Написал тест-кейсы
Дизайнер:
- Задал длительность и easing
- Подтвердил визуал
- Проверил поведение на разных задержках
QA:
- Проверил критерии приёмки
- Протестировал на мобильных и в режиме reduced motion
Совместимость и миграция
- В старых версиях AnimatePresence существовал проп exitBeforeEnter; в новых версиях используется mode=’wait’. Если мигрируете — проверьте используемую версию Framer Motion и замените API согласно документации.
- При SSR обязательно убедитесь, что компонент корректно гидратируется на клиенте перед запуском сложных анимаций.
Security и приватность
Анимации не передают пользовательские данные. Тем не менее, избегайте просмотра чувствительных данных во время анимации, если экран может быть записан.
Пример: анимация списка с удалением элемента
function TodoList({ items, remove }) {
return (
{items.map(item => (
{item.text}
))}
)
}Советы: анимация высоты часто требует либо вычислений, либо использования layout-анимаций Framer Motion.
Мерчантинговая диаграмма решения (decision flow)
flowchart TD
A[Нужна анимация при добавлении/удалении?] -->|Да| B[Нужна сложная логика или последовательность?]
A -->|Нет| C[CSS-переходы]
B -->|Да| D[Использовать Framer Motion]
B -->|Нет| E[react-transition-group или CSS]Сводка
Framer Motion упрощает создание плавных входных и выходных анимаций в React благодаря motion и AnimatePresence. Для простых эффектов используйте CSS; для интерактивных, последовательных и сложных переходов — Framer Motion. Всегда учитывайте доступность (prefers-reduced-motion) и влияние на размер бандла.
Ключевые этапы: дизайн → прототип → реализация → тестирование. Следуйте критериям приёмки и используйте предоставленные шаблоны и чек-листы для последовательной и безопасной интеграции анимаций.
Похожие материалы
Day.js в React: управление датой и временем
Понизить Windows 8 Pro до Windows 7 — инструкция
Диск-образ и работа с ISO в Windows 10
Режим совместимости Windows 11 — запуск старых программ