Створення інтерактивних анімацій за допомогою React Spring
Ця стаття присвячена React Spring – бібліотеці анімації на основі JavaScript. Ми розглянемо її фічі, включаючи різні хуки та компоненти, і те, як використовувати їх у додатках.
Анімація в React-додатках постійно розвивається. Спочатку вона реалізовувалася за допомогою CSS-переходів, але зі зростанням складності додатків стало ясно, що потрібні потужніші інструменти. З’явилися бібліотеки анімації на основі JavaScript, такі як Framer Motion, Remotion та React Spring, кожна з яких пропонує унікальні можливості для створення анімації в React.
Ця стаття передбачає, що ви маєте наступне:
- є базове розуміння React та React Hooks;
- ви знайомі з синтаксисом JavaScript та JSX;
- у середовищі розробки встановлені Node.js та
npm
(абоyarn
); - є редактор коду – наприклад, Visual Studio Code.
Введення в React Spring
React Spring – це JavaScript-бібліотека для створення інтерактивних анімацій у React-додатках. На відміну від традиційної анімації на основі CSS або інших бібліотек анімації React, React Spring використовує анімацію на основі фізики, яка імітує реальні рухи та створює більш природний ефект.
Ці анімації можна застосувати до будь-якої властивості React-компонентів, включаючи положення, масштаб, непрозорість та багато іншого. Це робить його потужним інструментом для розробників, які бажають поліпшити досвід користувача React-додатків за допомогою захоплюючих анімацій.
Налаштування React Spring у проекті
Щоб анімувати компоненти в React проекті за допомогою React Spring, потрібно виконати такі кроки:
- Завантажити та встановити бібліотеку React Spring за допомогою
npm
абоyarn
:
npm install react-spring
yarn add react-spring
Ці команди встановлять бібліотеку react-spring та її залежності до каталогу проекту.
- Після встановлення React Spring потрібно імпортувати необхідні компоненти та хуки до компонентів React, щоб почати анімувати елементи. Це можна зробити за допомогою наступного синтаксису:
import { animated, (hook) } from 'react-spring'
У наведеному вище фрагменті коду ми імпортуємо дві залежності (хук та анімацію) з бібліотеки React Spring. Ось докладний опис того, як працює кожен із них, і чому їх необхідно імпортувати.
Animated
У React Spring анімований ( animated
) простір імен надає набір компонентів, які дозволяють анімувати елементи в програмі React. Ці компоненти являють собою анімовані версії стандартних HTML елементів, таких як <div>
, <span>
і <img>
. Ми можемо використовувати ці анімовані елементи замість звичайних HTML елементів та застосовувати до них анімації за допомогою хуків анімації React Spring.
Хукі
Для створення анімації у React-компонентах React Spring пропонує декілька хуків. Вони спрощують процес управління анімаціями та дозволяють легко інтегрувати їх у компоненти. Ось деякі з них:
- useSpring . Використовується здебільшого, оскільки створює одну пружинну анімацію, яка змінює дані з початкового стану до іншого.
- useTransition . Анімує додавання, видалення або перевпорядкування елементів списку. Вона керує життєвим циклом анімації елементів, коли вони входять або виходять із DOM, забезпечуючи плавні переходи між різними станами списку.
- useTrail . Використовується для створення кількох пружинних анімацій, що створюють ефект “сліду”, коли кожна пружина слідує за попередньою або відстає від неї.
- useChain . Як і ланцюжок, використовується визначення послідовності анімацій із зазначенням порядку їх проходження.
- useSprings . Хоча це схоже на
useSpring
,useSprings
використовується для управління кількома анімаціями пружинними одночасно, в той час якuseSpring
управляє однією пружинною анімацією.
Щоб краще зрозуміти, як вони працюють, давайте розглянемо різні стилі анімації, яких можна досягти за допомогою кожного з цих хуків.
Використання useSpring для створення анімацій
Хук useSpring
React Spring використовується для створення анімації з використанням фізики пружини. Він дозволяє нам визначити початкову та кінцеву точки анімації та використовує свою бібліотеку для обробки переходу між ними. Наприклад:
const props = useSpring({
opacity: 1,
from: { opacity: 0 }
});
У цьому прикладі ми створили функцію, яка змінює непрозорість елемента від 0 до 1. Цю функцію можна викликати різних елементів залежно від ефектів анімації. Давайте розглянемо кроки, які потрібно зробити при використанні хука useSpring
для створення анімації.
По-перше, імпортуйте залежності, необхідні для анімації:
import { useSpring, animated } from "react-spring";
Далі нам потрібно визначити компонент та використовувати хук useSpring
для створення анімованих значень. Хук useSpring
приймає два основні аргументи:
- Об’єкт конфігурації. Він визначає властивості нашої анімації, включаючи:
- from: початковий стан анімованого значення (наприклад, opacity: 0)
- to: цільовий стан анімованого значення (наприклад, opacity: 1)
- config (необов’язково): об’єкт для точного настроювання фізичної поведінки пружини (наприклад, маса, натяг, тертя).
- Callback-функція (необов’язково). Ми можемо використовувати функцію для створення динамічної конфігурації на основі властивостей чи даних.
Анімацію useSpring
можна створити двома різними методами: за допомогою об’єктного літералу та за допомогою параметра функції.
Використання об’єктного літералу
Ми можемо визначити об’єкт із властивостями, які хочемо анімувати, наприклад, opacity
або color
і передати його в хук useSpring
. Такий підхід дозволяє прямо вказати цільові значення для анімації.
Щоб пояснити, як це працює, давайте створимо простий компонент, який анімує непрозорість елемента:
import React, { useState } from 'react';
import { useSpring, animated } from 'react-spring';
function App() {
const [isVisible, setIsVisible] = useState(false);
const opacityAnimation = useSpring({
opacity: isVisible ? 1 : 0,
config: {
tension: 200,
friction: 20
}
});
const toggleVisibility = () => setIsVisible(!isVisible);
return (
<div>
<button onClick={toggleVisibility} aria-label={isVisible ? 'Hide' : 'Show'}>
{isVisible ? 'Hide' : 'Show'}
</button>
<animated.div style={opacityAnimation}>
This text will fade in and out with spring physics.
</animated.div>
</div>
);
}
export default App;
У цьому фрагменті коду ми створюємо кнопку, яка перемикає видимість тексту. Для цього використовуються два хуки – useState
і useSpring
.
За допомогою useState
перевіряється, чи видно текст чи ні, і створюється анімація, що змінює непрозорість тексту залежно від цієї умови:
opacity: isVisible ? 1 : 0
Це дає ефект анімації при натисканні на кнопку, яка викликає функцію toggleVisibility()
.
Використання параметра функції
В якості альтернативи можна передати функцію в хук useSpring
. Ця функція отримує попередні значення анімації та повертає об’єкт з оновленими значеннями для анімації. Це дає більше контролю над тим, як анімація поводиться з часом:
const opacityConfig = {
tension: 300,
friction: 40,
};
// Define opacity animation with useSpring hook
const opacityAnimation = useSpring(() => ({
opacity: isVisible ? 1 : 0,
config: opacityConfig,
}));
При такому підході конфігурація (натяг та тертя) витягується в окремий об’єкт — opacityConfig
що забезпечує більшу гнучкість для динамічного управління на основі стану або властивостей.
Анімація елементів списку за допомогою UseTransition
UseTransition
– це хук React Spring, який анімує елементи в масивах при їх додаванні або видаленні з DOM. Він особливо корисний для створення плавної анімації у списках; при цьому він приймає список можливих конфігурацій:
from
визначає початкові стилі елементів, що входять у DOM.enter
задає стилі анімації при додаванні елементів. Ми можемо створювати багатоступінчасті анімації, надаючи масив об’єктів.leave
задає стилі, які застосовуються при видаленні елементів із DOM.update
керує тим, як анімувати зміни між наявними елементами.key
дозволяє явно визначити унікальний ключ кожного елемента, що у своє чергу допомагає визначити специфічні анімації окремих елементів.from
іto
з переходами: їх можна використовувати в рамкахenter
і для більш складних анімацій з початковими і кінцевими станами, що визначаються незалежноleave
.update
Щоб проілюструвати роботу useTransition
, давайте створимо компонент, який додає та видаляє елементи з масиву:
import React, { useState } from "react";
import { useTransition, animated } from "react-spring";
function App() {
const [items, setItems] = useState([]);
const addItem = () => {
const newItem = `Item ${items.length + 1}`;
setItems([...items, newItem]);
};
const removeItem = () => {
if (items.length === 0) return;
const newItems = items.slice(0, -1);
setItems(newItems);
};
const transitions = useTransition(items, {
from: { opacity: 0, transform: "translate3d(0, -40px, 0)" },
enter: { opacity: 1, transform: "translate3d(0, 0, 0)" },
leave: { opacity: 0, transform: "translate3d(0, -40px, 0)" },
});
return (
<div className="transitionDiv">
<div>
<button onClick={addItem}>Add Item</button>
<button onClick={removeItem}>Remove Item</button>
</div>
<div className="transitionItem">
{transitions((style, item) => (
<animated.div style={style} className ='list'>{item}</animated.div>
))}
</div>
</div>
);
}
export default App;
У цьому прикладі ми маємо компонент App
, який керує списком елементів. Він надає кнопки для динамічного додавання або видалення елементів зі списку. При натисканні на кнопку “Add Item” («Додати елемент) до масиву додається новий елемент, а при натисканні на кнопку “Remove Item” («Видалити елемент») з масиву видаляється останній елемент.
Хук useTransition
використовується для керування переходами елементів у масиві. Коли масив змінюється (в результаті додавання або видалення елементів), useTransition
обробляє анімацію для цих змін відповідно до заданої конфігурації (визначеної властивостями from
, enter
і leave
).
Масиви анімацій без змін
Якщо в масиві немає динамічних змін, таких як додавання або видалення елементів, useTransition
все одно можна використовувати для анімації кожного елемента в масиві. Наприклад:
import { useTransition, animated } from "@react-spring/web";
import "./App.css";
const name = "Product1";
const name1 = "Product2";
const name2 = "Product3";
function App({ data = [name, name1, name2] }) {
const transitions = useTransition(data, {
from: { scale: 0 },
enter: { scale: 1 },
leave: { scale: 0.5 },
config: { duration: 2500 },
});
return transitions((style, item) => (
<div className="nameBody">
<animated.div style={style} className="nameDiv">
{item}
</animated.div>
</div>
));
}
export default App;
У цьому прикладі компонент App
відображає список елементів та застосовує анімацію під час кожного завантаження сторінки.
Створення послідовних анімацій за допомогою useTrail
Анімація useTrail
використовується для створення серії анімованих переходів для групи або списку елементів інтерфейсу користувача.
На відміну від традиційних методів анімації, які анімують елементи окремо, useTrail
дозволяє анімувати елементи один за одним, створюючи тим самим ефект сліду (trail). Зазвичай це використовується при створенні динамічних списків, галерей зображень, переходів між сторінками або інших сценаріїв, де елементи повинні анімуватися послідовно.
Ось основна структура синтаксису:
const trail = useTrail(numberOfItems, config, [trailOptions]);
Давайте розберемося:
NumberOfItems
. Це необхідне число, яке визначає скільки елементів ми хочемо анімувати в trail.config
. Об’єкт, що визначає властивості анімації для кожного елемента в trail. Кожен ключ в об’єкті представляє властивість анімації, і його значення може ґрунтуватися на нашій передбачуваній анімації. Наприклад:
from: { opacity: 0, transform: 'translateX(50%)' },
to: { opacity: 1, transform: 'translateX(0)' },
transition: {
duration: 500,
easing: 'easeInOutCubic',
},
trailOptions
(не обов’язково). Це масив додаткових опцій для trail. Деякі спільні опції:trailKey
: функція для створення унікальних ключів для кожного елемента в trail (корисно для узгодження з React).reset
: функція для скидання всіх анімацій у trail.
Давайте подивимося, як це працює:
import React, { useState, useEffect } from "react";
import { useTrail, animated } from "react-spring";
function App() {
const [items, setItems] = useState([
{ id: 1, content: "This is a div illustrating a trail animation" },
{ id: 2, content: "This is a div illustrating a trail animation" },
{ id: 4, content: "This is a div illustrating a trail animation" },
{ id: 5, content: "This is a div illustrating a trail animation" },
]);
[]);
const trail = useTrail(items.length, {
from: { opacity: 1, transform: "translateY(0px)" },
to: { opacity: 0, transform: "translateY(100px)" },
delay: 400, // Add a delay between animations
duration: 2000, // Customize the animation duration
});
return (
<div className="container">
{trail.map((props, index) => (
<animated.div key={items[index].id} style={props} className="item">
{items[index].content}
</animated.div>
))}
</div>
);
}
export default App;
У наведеному вище фрагменті коду ми створюємо компонент CardCarousel
– він використовує хук useTrail
для анімації кожної картки каруселі залежно від довжини масивних елементів.
const trail = useTrail(items.length, {
from: { opacity: 1, transform: "translateY(0px)" },
to: { opacity: 0, transform: "translateY(100px)" },
delay: 400, // Add a delay between animations
duration: 2000, // Customize the animation duration
});
Тут задаються початковий і кінцевий стан анімації (від і до), і навіть конфігурація переходу (тривалість і пом’якшення), що впливає спосіб відображення анімації.
Рендеринг кожної картки
Компонент повертає <div>
з класом card-carousel
та відображає масив trail для рендерингу кожної анімованої картки. Потім кожна картка обертається в компонент animated.div
із застосуванням стилів анімації (непрозорість та трансформація), заданих у хуку useTrail
:
return (
<div className="container">
{trail.map((props, index) => (
<animated.div key={items[index].id} style={props} className="item">
{items[index].content}
</animated.div>
))}
</div>
);
Підготовка послідовності анімацій за допомогою useChain
На відміну від окремих анімацій, useChain
використовується для зв’язування кількох анімацій та задає послідовність виконання заданих анімацій. Це особливо корисно при створенні динамічних інтерфейсів, де елементи анімуються один за одним.
Давайте розглянемо синтаксис.
UseChain
приймає масив посилань на анімацію та необов’язковий об’єкт конфігурації. Кожне посилання на анімацію є окремою анімацією, і вони виконуються в тому порядку, в якому з’являються в масиві. Ми також можемо вказати час затримки кожної анімації, щоб контролювати час виконання послідовності за допомогою цього синтаксису:
useChain([ref1, ref2, ref3], { delay: 200 });
Щоб проілюструвати, як це працює, давайте створимо компонент, який застосовує дві анімації до різних елементів і керує ними за допомогою useChain
:
import "./App.css";
import React, { useRef } from "react";
import {
useTransition,
useSpring,
useChain,
animated,
useSpringRef,
} from "react-spring";
const data = ["", "", "", ""];
function App() {
const springRef = useSpringRef();
const springs = useSpring({
ref: springRef,
from: { size: "20%" },
to: { size: "100%" },
config: { duration: 2500 },
});
const transRef = useSpringRef();
const transitions = useTransition(data, {
ref: transRef,
from: { scale: 0, backgroundColor: "pink" },
enter: { scale: 1, backgroundColor: "plum" },
leave: { scale: 0, color: "pink" },
config: { duration: 3500 },
});
useChain([springRef, transRef]);
return (
<animated.div
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
height: "400px",
width: springs.size,
background: "white",
}}
>
{transitions((style, item) => (
<animated.div
style={{
width: "200px",
height: "200px",
display: "flex",
justifyContent: "center",
alignItems: "center",
textAlign: "center",
marginLeft: "50px",
color: "white",
fontSize: "35px",
borderRadius: "360px",
...style,
}}
className="products"
>
{item}
</animated.div>
))}
</animated.div>
);
}
export default App;
У наведеному вище коді ми створюємо дві різні анімації, використовуючи useString
і useTransition
, а також використовуємо useChain
для керування різними анімаціями:
useChain([springRef, transRef]);
Створення декількох анімацій за допомогою хука useSprings
Як ми вже говорили, useSprings
використовується для створення кількох пружинних анімацій одночасно і кожна з цих анімацій має свої конфігурації. Це дозволяє нам анімувати кілька елементів або властивостей незалежно один від одного у межах одного компонента. Наприклад:
import { useSprings, animated } from "@react-spring/web";
function App() {
const [springs, api] = useSprings(
3,
() => ({
from: { scale: 0, color: "blue" },
to: { scale: 1, color: "red" },
config: { duration: 2500 },
}),
[]
);
return (
<div>
{springs.map((props) => (
<animated.div style={props} className="springsText">
_______
</animated.div>
))}
</div>
);
}
export default App;
У цьому прикладі useSprings
керує масивом пружинних анімацій, кожна з яких представляє анімацію для одного елемента масиві елементів. Кожен елемент у списку пов’язаний із конфігурацією spring, яка визначає початкові та цільові значення для властивостей кольору та масштабу. Потім React Spring анімує кожен елемент на основі конфігурації.
Висновок
React Spring – це потужна бібліотека анімації, яка дозволяє створювати чудові інтерактивні анімації в React-додатках. Як ми побачили, ці анімації можуть застосовуватись до різних елементів у проектах.
Використовуючи можливості React Spring, ми можемо досягти більш плавних переходів із більш природними ефектами, а також отримати більший контроль над анімацією.