React Spring 5 useResize(), useInView(), indexed useSprings()
The useResize(), a useSpring() abstraction, returns the useRef() container width/height props. Its onChange() will trigger on window resize.
//width returned in px
let quad = useRef(null)
const { width, height } = useResize({
container: quad,
onChange: ({value: {width} })=> {
console.log( width )
}
})
<div>
<div style={{ width: "50vw", height: "30vh", background: "yellow" }} ref={quad}>
</div>
</div>
Animated useSpring() with useInView() hook
The useInView() hook tracks an element's visibility relative to the viewpoint. It will return the useRef() for the target element and the boolean result of the Intersection Observer API
import { animated, useSpring, useInView} from '@react-spring/web'
let [ref, inview] = useInView({
//Element's visibility percentage that will trigger the useInView() callback
threshold: 0.5, //independently of scroll direction
rootMargin: '0px 0px -20% 0%', //margins around the element (adds to threshold)
once: true, //will trigger the API once
})
let springs = useSpring({
opacity: inview ? 1 : 0,
y: inview ? 0 : 100,
backgroundColor: inview ? "red" : "pink",
})
<div ref={ref}>
<animated.div style={springs}>
{inview ? "Visible" : "inVisible" }
</animated.div>
</div>

Rendering useSprings() with index-based style properties
The useSprings() hook renders a number of indexed springs with shared props, their indexes can set their individual properties and be used to animate specific useSpring().
//We render 3 useSprings() each with x based on their array index
//The index conditional is needed in api.start() to not animate every element
let [lista, listaapi] = useSprings(3, i => ({
from: {x: 0},
to: {x: i * 100}
})
listaapi.start(i =>{
if (i !== 2) return
return {x: 400}
})
We can mimic a useChain() sequential animation with useSprings(), we distance the delay of each element by their index, the effect depends on the duration-delay ratio.
//Each letter (and empty space) needs to be centered and have its own area
//We use the map() index for the useSprings() index
//3 letters will share their animation time
let star = "Kai Ashen"
let [nome, setNome] = useState(star.split(""))
let [mosso, mossoApi] = useSprings(nome.length, (i)=>({
from: { top: 0 },
to: [ {top: 15}, {top: -15}, {top: 0} ],
delay: (i * 200),
config: { duration: 600 }
}) )
<div className="bg-success" style={{ height: "30vh", width: "55vw" }}>
{nome.map((cont, index)=>(
<animated.h1 className=" position-relative"
key={index} style={{width: "0.7em", height: "1em", top: mosso[index].top }}>
{cont}
</animated.h1>)
)}
</div>


We can set transition on the style object and the transition style property on the looped map() elements, without using springs().
const itemStyle = {
...
transition: "top 2s, left 2s"
};
const [items, set] = useState(
[1, 2, 3, 4, 5, 6, 7].map((item, i) => ({ position: i, value: item }))
);
<>
{items.map(({ position, value }) => (
<div style={{ ...itemStyle,
top: `${Math.floor(position/5) * 100}px`,
left: `${(position%5) * 100}px`}}>
{value}
</div>
))}
</>
1
1
1
1
1
Last updated
Was this helpful?