Условный рендеринг — это управление отображением элементов интерфейса в зависимости от состояния приложения. В связке с библиотекой Popmotion он приобретает дополнительную глубину, позволяя не просто показывать или скрывать элементы, а управлять их появлением, исчезновением и переходами с помощью анимаций.
В основе лежит идея: состояние определяет не только наличие элемента в DOM, но и его визуальное поведение.
В классическом JavaScript условный рендеринг реализуется через:
if / elseПри использовании Popmotion добавляется промежуточный слой — анимация, которая реагирует на изменение состояния.
Пример базовой зависимости:
let isVisible = false;
function toggle() {
isVisible = !isVisible;
render();
}
Без анимации элемент просто появляется или исчезает. С Popmotion добавляется плавный переход:
import { tween, styler } from "popmotion";
const box = document.querySelector(".box");
const style = styler(box);
function show() {
tween({
from: { opacity: 0, y: -50 },
to: { opacity: 1, y: 0 },
duration: 300
}).start(style.set);
}
function hide() {
tween({
from: { opacity: 1, y: 0 },
to: { opacity: 0, y: -50 },
duration: 300
}).start(style.set);
}
Ключевая проблема условного рендеринга с анимациями — момент удаления элемента из DOM.
Если элемент удаляется сразу, анимация исчезновения не успевает выполниться.
function hideElement(element, onComplete) {
const style = styler(element);
tween({
from: { opacity: 1 },
to: { opacity: 0 },
duration: 300
}).start({
update: style.set,
complete: () => {
element.remove();
if (onComplete) onComplete();
}
});
}
Здесь элемент:
Создание элементов можно обернуть в функцию:
function createBox() {
const el = document.createElement("div");
el.classList.add("box");
document.body.appendChild(el);
return el;
}
Связка с условием:
let currentBox = null;
function render(isVisible) {
if (isVisible && !currentBox) {
currentBox = createBox();
animateIn(currentBox);
}
if (!isVisible && currentBox) {
animateOut(currentBox, () => {
currentBox = null;
});
}
}
Так обеспечивается:
Popmotion предоставляет Actions — абстракцию над анимациями.
Пример с использованием tween как Action:
import { tween } from "popmotion";
function fade(element, from, to) {
return tween({ from, to, duration: 300 }).start(v => {
element.style.opacity = v;
});
}
Условное использование:
if (isVisible) {
fade(box, 0, 1);
} else {
fade(box, 1, 0);
}
Popmotion позволяет комбинировать анимации:
import { parallel, tween } from "popmotion";
function animateIn(element) {
const style = styler(element);
parallel(
tween({ from: 0, to: 1 }),
tween({ from: -100, to: 0 })
).start(([opacity, y]) => {
style.set({ opacity, y });
});
}
import { chain } from "popmotion";
chain(
tween({ from: 0, to: 1, duration: 200 }),
tween({ from: 1, to: 0.8, duration: 100 })
).start(v => {
element.style.opacity = v;
});
Такая композиция особенно полезна при:
Popmotion поддерживает реактивный стиль через value.
import { value, tween } from "popmotion";
const visibility = value(0, v => {
box.style.opacity = v;
});
Изменение состояния:
function show() {
tween({ to: 1 }).start(visibility);
}
function hide() {
tween({ to: 0 }).start(visibility);
}
Здесь:
visibility) хранится отдельноПри работе со списками возникает задача:
function addItem(container) {
const item = document.createElement("div");
item.classList.add("item");
container.appendChild(item);
tween({
from: { opacity: 0, scale: 0.8 },
to: { opacity: 1, scale: 1 }
}).start(styler(item).set);
}
function removeItem(item) {
const style = styler(item);
tween({
to: { opacity: 0, scale: 0.8 }
}).start({
update: style.set,
complete: () => item.remove()
});
}
При быстром переключении состояния важно:
let animation;
function animate(to) {
if (animation) animation.stop();
animation = tween({ to }).start(v => {
box.style.opacity = v;
});
}
Использование:
animate(isVisible ? 1 : 0);
Popmotion удобно комбинируется с обработчиками событий:
button.addEventListener("click", () => {
isVisible = !isVisible;
render(isVisible);
});
С добавлением анимации:
Рекомендуется разделять:
Пример структуры:
// state
let isVisible = false;
// animation
function animateIn(el) { /* ... */ }
function animateOut(el, done) { /* ... */ }
// render
function render() { /* ... */ }
Это позволяет:
1. Мгновенное удаление элемента
2. Отсутствие контроля над состоянием
3. Перезапуск анимаций без остановки
4. Смешивание логики
Вместо удаления элемента можно:
opacitypointer-eventsfunction hide(element) {
tween({ to: 0 }).start(v => {
element.style.opacity = v;
element.style.pointerEvents = "none";
});
}
Преимущества:
Popmotion поддерживает различные easing-функции:
import { easing, tween } from "popmotion";
tween({
to: 1,
ease: easing.easeInOut
}).start(v => {
box.style.opacity = v;
});
Это позволяет:
Эффективная схема:
Такой подход превращает условный рендеринг из простой логической операции в полноценный инструмент управления пользовательским опытом.