Given a list:
li {
display: inline-block;
color: #000000;
}
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
Using react-spring, I am trying to animate the colour of each item in a list (one by one) every 3 seconds and loop from start to finish.
For example:
I can get an individual item to show and colour to update and then hides (as only 1 item from the list is being animated), but not the whole list to show and change the colour of each item 1 by 1.
const ColourListTransition = (items, delay) => {
const [index, setIndex ] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setIndex((state) => ( state + 1 ) % items.length);
}, delay);
return () => clearInterval(interval);
}, []);
return useTransition(items[index], {
from: { color: '#000000' },
enter: { color: "#FF0000" },
leave: { color: "#000000" },
loop: true,
config: config.molasses
})
}
{ ColourListTransition(['item 1', 'item 2', 'item 3', 'item 4'], 3000)(({ color }, item) => (
<animated.li
key={ item }
style={ { color, display: 'inline-block', listStyleType: 'none' } }
>
{ item }
</animated.li>
)) }
I played around with useTransition
but I just could not figure it out. It was easy when I switched to using useSprings
instead. So this might not be the most elegant solution but it works.
We create an array of spring animations which correspond to the items in your list. The color of each item is based on whether its index matches the active index from state. enter
and leave
don't really come into play here since you always have same 4 items in your array. I kept your useState
and useEffect
hooks the same.
import React, { useState, useEffect } from "react";
import { animated, config, useSprings } from "@react-spring/web";
const ColourListTransition = ({delay, items, activeColor, inactiveColor}) => {
const [index, setIndex] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setIndex((state) => (state + 1) % items.length);
}, delay);
return () => clearInterval(interval);
}, []);
const [springs] = useSprings(
// count
items.length,
// properties as a function of index
(i) => ({
// determine the current color based on the index
color: i === index ? activeColor : inactiveColor,
// all items start out black
from: { color: inactiveColor },
config: config.molasses
}),
// dependency on index state
[index]
);
return (
<ul>
{springs.map(({ color }, i) => (
<animated.li
key={items[i]}
style={{ color, display: "inline-block", listStyleType: "none" }}
>
{items[i]}
</animated.li>
))}
</ul>
);
};
export default function App() {
return (
<ColourListTransition
items={["item 1", "item 2", "item 3", "item 4"]}
delay={3000}
activeColor={"#FF0000"}
inactiveColor={"#000000"}
/>
);
}