#reactjs #react-hooks #react-spring
Вопрос:
Как мы можем анимировать отображение записей с помощью react-spring
. Можем ли мы вызвать функцию useTransition
in useEffect() ? Я хотел бы анимировать записи снизу вверх одну за другой, когда пользователь переходит на страницу. Я пробовал ниже, ничего не происходит..? Любой совет был бы действительно полезен.
https://codesandbox.io/s/inspiring-snowflake-34dpx?file=/src/App.js:711-881
import { useEffect, useState } from "react";
import { useTransition, animated } from "react-spring";
import "./styles.css";
const array1 = [
{ id: "1", name: "Cat" },
{ id: "2", name: "Dog" },
{ id: "3", name: "Cow" }
];
export default function App() {
const [list, setList] = useState(array1);
const height = 20;
useEffect(() => {
setList(array1);
}, []);
const transitions = useTransition(
Object.entries(list).map((data, i) => ({ ...data, y: i * height })),
{
from: { position: "absolute", opacity: 0 },
enter: { height: 0, opacity: 1 },
leave: { opacity: 0 },
config: { tension: 220, friction: 120 }
}
);
return (
<div className="App">
{/* {Object.entries(list).map((item, index) => (
<div key={item.id} className="record">
<span key={item.name}>{item.name}</span>
</div>
))} */}
{Object.entries(transitions).map(({ item, props, key }) => (
<animated.div key={key} style={{ ...props, position: "absolute" }}>
<div key={item.id} className="record">
<span key={item.name}>{item.name}</span>
</div>
</animated.div>
))}
</div>
);
}
Ответ №1:
transitions
Переменная-это функция, поэтому вы не хотите Object.entries(transitions).map()
. Это не ошибка, потому что функции в Javascript также являются объектами, но это ничего не даст, потому что массив записей является пустым массивом.
Вы хотите вызвать transitions
функцию, которая является своего рода картографом.
{transitions((props, item, key) => (
Ну а теперь я вижу голубую коробку вместо белого экрана. Так что это небольшой прогресс, но еще многое предстоит сделать.
Если вы console.log
выберете свой item
объект, вы увидите, что он выглядит неправильно.
Object.entries(list).map((data, i) => ({ ...data, y: i * height }))
Вы сопоставляете массив записей объекта, поэтому data
переменная представляет собой массив, содержащий ключ и значение. Ты этого не хочешь. list
это уже массив, так что бросьте Object.entries
.
list.map((data, i) => ({ ...data, y: i * height })),
Теперь я вижу «Корову»! Но два других скрыты, потому что ваши предметы появляются друг над другом.
Вы используете абсолютное позиционирование, но не передали позицию компоненту. Поскольку вы не анимируете это значение, это свойство item
скорее чем props
.
<animated.div key={key} style={{ ...props, position: "absolute", top: item.y }}>
Теперь я вижу всех троих!
Но перекрывающиеся фоновые блоки, вероятно, не то, что вы предполагали. Я не уверен, что вы имели в виду на самом деле, потому что у вас есть a height
20
в вашем JS и 100px
в вашем CSS. У вас также есть height
свойство в вашей анимации, но оно ничего не делает.
Все элементы вашего списка имеют height: 0px
, потому что вы задаете высоту 0
в enter
свойстве, которое вызывается, когда элемент впервые входит в список. С другой стороны, from
свойство задает начальные значения, от которых элемент анимируется, поэтому, возможно, вы хотите иметь начальное значение height: 0
in from
и некоторое конечное значение height
in enter
.
Вы можете анимировать высоту фона, но это не повлияет на высоту текста. Возможно, вам захочется transform
что-то подобное scaleY
. Вы можете использовать преобразование вместо анимации высоты (все элементы начинаются в их конечном положении и растут на месте) или рядом с анимацией высоты (все элементы начинаются вместе вверху и растут вниз).
Вот один из возможных эффектов: Ссылка на песочницу кода
style.css
.App {
font-family: sans-serif;
text-align: center;
}
.record {
width: 300px;
background-color: aqua;
margin: 20px 0;
color: #1f1d1d;
}
.title {
font-size: 30px;
padding: 35px;
}
App.js
import { useState } from "react";
import { useTransition, animated } from "react-spring";
import "./styles.css";
const array1 = [
{ id: "1", name: "Cat" },
{ id: "2", name: "Dog" },
{ id: "3", name: "Cow" }
];
export default function App() {
const [list, setList] = useState(array1);
const transitions = useTransition(list, {
from: { opacity: 0, scaleY: 0 },
enter: { opacity: 1, scaleY: 1 },
leave: { opacity: 0 },
config: { tension: 220, friction: 120 }
});
return (
<div className="App">
{transitions((props, item, key) => {
console.log(props, item, key);
return (
<animated.div key={key} style={{ ...props }} className="record">
<div className="title">{item.name}</div>
</animated.div>
);
})}
</div>
);
}
Редактировать
Как и было запрошено, снизу вверх один за другим:
export default function App() {
const height = window.innerHeight;
const [list, setList] = useState(array1);
const transitions = useTransition(list, {
from: { opacity: 0, translateY: height },
enter: { opacity: 1, translateY: 0 },
leave: { opacity: 0 },
config: { tension: 220, friction: 120 },
trail: 200
});
return (
<div className="App">
{transitions((props, item, key) => {
console.log(props, item, key);
return (
<animated.div key={key} style={{ ...props }} className="record">
<div className="title">{item.name}</div>
</animated.div>
);
})}
</div>
);
}
Комментарии:
1. ..Большое вам спасибо, может ли что-то двигаться от нижней части страницы к верхней ..один за другим other…is это возможно ?
2. Да, но для этого может потребоваться знать высоту документа?. Вы можете использовать абсолютное положение или преобразование перевода для движения. Для «одного за другим» вы можете использовать
trail
свойство.