Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Pager with Spring Transitions
import React, { useState, useEffect } from 'react'
import { useSpring, animated, interpolate } from 'react-spring'
// let's add some transitions to the pager component when the activeIndex changes
function Pager({ children, activeIndex }) {
const offset = activeIndex * 100 * -1
// translateX will now represent a spring value that we will animate
// we'll set the initial value to our first offset here:
const [{ translateX }, set] = useSpring(() => ({
translateX: offset,
}))
// when the offset updates, we want to update the translateX value
// so that the spring will fire again:
useEffect(() => {
set({ translateX: offset })
}, [offset, set])
// update the container view to an animated.div
// we'll use the interpolate() function to translate with our spring values
// this gives us a nice spring animation to our page transitions
return (
<animated.div
style={{
border: 'thin solid blue',
position: 'relative',
height: '100%',
width: '100%',
transform: interpolate(
[translateX],
(translateX) => `translateX(${translateX}%)`,
),
}}>
{React.Children.map(children, (element, index) => {
return (
<div
style={{
...absoluteFill,
transform: `translateX(${index * 100}%)`,
}}>
{element}
</div>
)
})}
</animated.div>
)
}
const absoluteFill = {
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
top: 0,
}
const PAGE_SIZE = 200
// this will represent a consumer component or any part of your application
function App() {
// all we need to pass are children and an activeIndex prop to our pager component
const [activeIndex, setActiveIndex] = useState(0)
const children = Array.from({ length: 10 }).map((c, i) => (
<h1 key={i} style={{ textAlign: 'center' }}>
Index {i}
</h1>
))
return (
<div>
<div
style={{
width: PAGE_SIZE,
height: PAGE_SIZE,
display: 'flex',
margin: 'auto',
padding: '5px',
border: 'thin solid red',
}}>
<Pager activeIndex={activeIndex}>{children}</Pager>
</div>
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'space-around',
}}>
<strong style={{ margin: '5px 0' }}>activeIndex: {activeIndex}</strong>
<button
style={{ margin: '5px 0' }}
onClick={() => setActiveIndex(activeIndex + 1)}>
Increment
</button>
<button
style={{ margin: '5px 0' }}
onClick={() => setActiveIndex(activeIndex - 1)}>
Decrement
</button>
</div>
</div>
)
}
export default App
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.