Библиотека MUI (Material-UI) предоставляет мощные возможности для создания динамичных и отзывчивых интерфейсов. Одним из инструментов, который позволяет плавно анимировать элементы списка при их добавлении, удалении или изменении, является компонент TransitionGroup, который интегрируется с MUI через библиотеку react-transition-group. Он особенно полезен для списков с динамическим содержимым, таких как чаты, уведомления или галереи.
TransitionGroup не рендерит визуальные элементы сам
по себе. Он управляет жизненным циклом анимации дочерних компонентов,
используя внутренние события enter, exit и
appear. Каждый элемент списка оборачивается в компонент
Transition или его производные, например
CSSTransition, для задания конкретной анимации.
Ключевые свойства TransitionGroup:
component – указывает тип HTML-элемента, который
обернёт все дочерние компоненты (по умолчанию div).children – элементы, которые будут анимироваться.appear – если true, элементы будут
анимироваться при первоначальном появлении.Для примера возьмём компонент List из MUI и реализуем анимацию добавления и удаления элементов.
import React, { useState } from "react";
import { List, ListItem, ListItemText, Button } from "@mui/material";
import { TransitionGroup, CSSTransition } from "react-transition-group";
import "./listAnimations.css";
export default function AnimatedList() {
const [items, setItems] = useState(["Элемент 1", "Элемент 2", "Элемент 3"]);
const addItem = () => {
const nextIndex = items.length + 1;
setItems([...items, `Элемент ${nextIndex}`]);
};
const removeItem = (index) => {
setItems(items.filter((_, i) => i !== index));
};
return (
<div>
<Button variant="contained" onCl ick={addItem}>Добавить элемент</Button>
<List>
<TransitionGroup>
{items.map((item, index) => (
<CSSTransition
key={item}
timeout={300}
classNames="fade"
>
<ListItem
secondaryAction={
<Button onCl ick={() => removeItem(index)}>Удалить</Button>
}
>
<ListItemText primary={item} />
</ListItem>
</CSSTransition>
))}
</TransitionGroup>
</List>
</div>
);
}
Файл listAnimations.css определяет стили для классов,
которые создает CSSTransition: fade-enter,
fade-enter-active, fade-exit,
fade-exit-active.
.fade-enter {
opacity: 0;
transform: translateY(-10px);
}
.fade-enter-active {
opacity: 1;
transform: translateY(0);
transition: opacity 300ms, transform 300ms;
}
.fade-exit {
opacity: 1;
transform: translateY(0);
}
.fade-exit-active {
opacity: 0;
transform: translateY(10px);
transition: opacity 300ms, transform 300ms;
}
Особенности:
fade-enter – начальное состояние при добавлении
элемента.fade-enter-active – состояние анимации, которое
применяется после начала перехода.fade-exit – начальное состояние перед удалением.fade-exit-active – состояние анимации при
удалении.MUI предлагает компонент Collapse, который можно использовать вместе с TransitionGroup для создания более естественных вертикальных анимаций, особенно в списках с переменной высотой элементов.
import { Collapse } from "@mui/material";
<TransitionGroup>
{items.map((item) => (
<Collapse key={item}>
<ListItem>
<ListItemText primary={item} />
</ListItem>
</Collapse>
))}
</TransitionGroup>
Преимущества использования Collapse:
При фильтрации или сортировке списка важно правильно управлять
ключами и состоянием, чтобы элементы, которые остаются, не анимировались
заново. Для этого лучше хранить массив с уникальными идентификаторами и
использовать их в качестве key.
items.map(item => (
<CSSTransition key={item.id} timeout={300} classNames="fade">
<ListItem>
<ListItemText primary={item.text} />
</ListItem>
</CSSTransition>
));
TransitionGroup и CSSTransition
совместимы с SSR, но анимации на сервере не выполняются. Поэтому для
элементов, которые изначально рендерятся на сервере, можно использовать
проп appear={true} или управлять стилями через MUI
sx/Theme, чтобы элементы выглядели корректно до завершения клиентской
анимации.
Стили анимации можно комбинировать с системой тем MUI:
<ListItem
sx={{
bgcolor: "background.paper",
"&.fade-enter": { opacity: 0 },
"&.fade-enter-active": { opacity: 1, transition: "opacity 300ms" },
}}
>
<ListItemText primary={item} />
</ListItem>
Это позволяет создавать единый визуальный стиль анимаций, который автоматически реагирует на светлую или тёмную тему.
TransitionGroup в MUI позволяет создавать интерактивные списки с плавными и адаптивными анимациями, интегрируя react-transition-group, MUI-компоненты и темы, обеспечивая высокое качество UX в динамических интерфейсах.