Shared Element Transitions (SET) — это техника анимации, при которой один и тот же визуальный элемент плавно перемещается между двумя разными маршрутами, создавая эффект непрерывного перехода. В React Router эта концепция реализуется через сочетание маршрутизации, состояния компонентов и анимационных библиотек, таких как Framer Motion.
Идея SET заключается в идентификации общих элементов на двух маршрутах и синхронизации их анимации при смене маршрута. Основные шаги включают:
Для демонстрации используется комбинация BrowserRouter,
Routes и Route. Основная задача — корректно
обрабатывать состояние элемента между маршрутами:
import { BrowserRouter as Router, Routes, Route, useLocation } from "react-router-dom";
import { AnimatePresence, motion } from "framer-motion";
import Home from "./Home";
import Detail from "./Detail";
function App() {
const location = useLocation();
return (
<AnimatePresence mode="wait">
<Routes location={location} key={location.pathname}>
<Route path="/" element={<Home />} />
<Route path="/detail/:id" element={<Detail />} />
</Routes>
</AnimatePresence>
);
}
export default function Root() {
return (
<Router>
<App />
</Router>
);
}
Ключевые моменты:
AnimatePresence отвечает за анимацию
выхода элементов из DOM.location.key или
location.pathname используется для отслеживания
изменений маршрута, что позволяет корректно синхронизировать
анимацию.motion.Чтобы два разных маршрута понимали, что один элемент является общим,
используется уникальный идентификатор. В библиотеке Framer Motion
применяется атрибут layoutId:
// Home.js
import { Link } from "react-router-dom";
import { motion } from "framer-motion";
export default function Home() {
return (
<div>
<Link to="/detail/1">
<motion.img
src="/image1.jpg"
alt="Item"
layoutId="image-1"
/>
</Link>
</div>
);
}
// Detail.js
import { motion } from "framer-motion";
export default function Detail() {
return (
<motion.div>
<motion.img
src="/image1.jpg"
alt="Item"
layoutId="image-1"
/>
</motion.div>
);
}
layoutId — уникальный ключ, связывающий
элементы на разных маршрутах. Framer Motion автоматически анимирует
изменения позиции, размера и других свойств.
Для достижения эффекта плавного перемещения можно настроить свойства анимации:
<motion.img
src="/image1.jpg"
layoutId="image-1"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.5, ease: "easeInOut" }}
/>
Здесь:
initial — начальное состояние элемента
при монтировании.animate — конечное состояние.exit — состояние при
размонтировании.transition — параметры анимации
(длительность, кривизна).Если необходимо анимировать несколько общих элементов, каждому
присваивается уникальный layoutId. Например:
<motion.div layoutId="card-1">Карточка 1</motion.div>
<motion.div layoutId="card-2">Карточка 2</motion.div>
При переходе на другой маршрут с идентичными layoutId
элементы будут плавно перемещаться на новые позиции, сохраняя визуальную
непрерывность.
location.pathname или location.key в
Routes, чтобы анимация срабатывала корректно.<motion.div
layoutId="card-1"
style={{ borderRadius: 20 }}
animate={{ borderRadius: 0 }}
/>
<motion.div
className="overlay"
initial={{ opacity: 0 }}
animate={{ opacity: 0.5 }}
exit={{ opacity: 0 }}
/>
motion
можно анимировать разные свойства (например, смещение фона), чтобы
создать более глубину в переходе.will-change и GPU-ускоренные свойства
(transform, opacity) для плавной
анимации.motion-компонентов,
особенно при списках или сетках.Shared Element Transitions позволяют создать эффект визуальной непрерывности при навигации, делая интерфейс React-приложений более динамичным и интерактивным. Ключевым аспектом является корректная идентификация общих элементов и синхронизация их состояния между маршрутами.