Package Exports
- react-spring
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (react-spring) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
npm install react-spring
Examples: Interpolation | Native rendering |Β Reveals | List transitions | Staggered | TodoMVC | DragList
Why π€
React-spring is a wrapper around a cooked down fork of Facebooks animated. It is trying to bridge Chenglou's React-motion and animated, as both have their pros and cons, but definitively could benefit from one another:
React-motion
- Declarative api that doesn't involve manual management of animations
- Covers most of the essentials (springs, lists, transitions, reveals, staggered animations)
- Performance can suffer because components are re-rendered every frame with fresh props
- Can't interpolate between raw state as it doesn't know colors, paths, gradients, etc.
Animated
- Interpolates most web privimites, units and patterns
- Efficiently writes to the dom directly instead of re-rendering components frame by frame
- Managing and orchestrating handles (starting/stopping/waiting/cleaning) can become a real chore
- Missing essential prototypes like mount/unmount transitions
So as you see, they're polar opposites and the strengths of one are the weaknesses of another. React-spring inherits React-motions api while you can feed it everything animated can interpolate. It also has support for animateds efficient native rendering.
Default rendering π
(Demo)
Like React-motion by default we'll render the receiving component every frame as it gives you more freedom to animate whatever you like. In many situations this will be ok.
import { Spring } from 'react-spring'
const App = ({ toggle }) => (
<Spring
// Default values, optional ...
from={{ opacity: 0 }}
// Will animate to ...
to={{
// Can be numbers, colors, paths, degrees, percentages, arrays, ...
start: toggle ? '#abc' : 'rgb(10,20,30)',
end: toggle ? 'seagreen' : 'rgba(0,0,0,0.5)',
stop: toggle ? '0%' : '50%',
scale: toggle ? 1 : 2,
rotate: toggle ? '0deg' : '45deg',
path: toggle
? 'M20,380 L380,380 L380,380 L200,20 L20,380 Z'
: 'M20,20 L20,380 L380,380 L380,20 L20,20 Z',
}}>
{({ color, scale, rotate, path, start, stop, end }) => (
<div style={{ background: `linear-gradient(to bottom, ${start} ${stop}, ${end} 100%)` }}>
<svg style={{ transform: `scale(${scale}) rotate(${rotate})` }}>
<g><path d={path} /></g>
</svg>
</div>
)}
</Spring>
)
Don't like the way render props wrap your code?
const Header = ({ children, ...styles }) => (
<h1 style={styles}>
{children}
</h1>
)
const App = ({ color, children }) => (
<Spring to={{ color }} render={Header}>
{children}
</Spring>
)
Et voilΓ ! Now you render a animated version of the Header
component! All props that Spring
doesn't recognize as its own will be spread over the receiving component, including children
if you use render
instead. It's actually faster as well since the function isn't recreated on every prop-change.
Native rendering π
(Demo)
Pass the native
flag for more performance. The animations will now be applied directly to the dom through requestAnimationFrame and the component will only render when it receives new props. The flag is available for all primitives (Spring, SpringTransition & SpringTrail).
Just be aware of the following conditions:
- It only animates standard styles and element props, the values you receive are opaque objects, not regular values
- Receiving elements must be
animated.[elementName]
, for instancediv
becomesanimated.div
- If you need to interpolate styles use the
template
string literal
import { Spring, animated, template } from 'react-spring'
const App = ({ toggle }) => (
<Spring
native
from={{ fill: 'black' }}
to={{
rotate: toggle ? '0deg' : '180deg',
scale: toggle ? 1 : 2,
path: toggle ? TRIANGLE : RECTANGLE,
}}>
{({ rotate, scale, path }) => (
<animated.svg style={{ transform: template`rotate(${rotate}) scale(${scale})` }}>
<g><animated.path d={path} /></g>
</animated.svg>
)}
</Spring>
)
Transitions πππππ
(Demo)
Use SpringTransition
and pass in your keys
. from
denotes base styles, enter
styles are applied when objects appear, leave
styles are applied when objects disappear. Keys and children have to match in their order!
import { SpringTransition } from 'react-spring'
const App = ({ items }) => (
<ul>
<SpringTransition
keys={items.map(item => item.key)}
from={{ opacity: 0, color: 'black', height: 0 }}
enter={{ opacity: 1, color: 'red', height: 18 }}
leave={{ opacity: 0, color: 'blue', height: 0 }}>
{items.map(item => styles => <li style={styles}>{item.text}</li>)}
</SpringTransition>
</ul>
)
}
You can use this prototype for two-state reveals, simply render a single child that you can switch out for another.
const App = ({ toggle }) => (
<SpringTransition
keys={toggle ? 'ComponentA' : 'ComponentB'}
from={{ opacity: 0 }}
enter={{ opacity: 1 }}
leave={{ opacity: 0 }}>
{toggle ? ComponentA : ComponentB}
</SpringTransition>
)
Trails/Staggered transitions πΎπΎπΎ
(Demo)
Create trailing animations by using SpringTrail
. The api is similar to SpringTransition
though it will assume your list is fixed. The items will interpolate in a staggered fashion, internally one spring follows the interpolated value of the previous one thereby creating a staggered chain.
import { SpringTrail } from 'react-spring'
const App = ({ items }) => (
<SpringTrail from={{ opacity: 0 }} to={{ opacity: 1 }} keys={items.map(item => item.key)}>
{items.map(item => styles => (
<div style={styles}>
{item.text}
</div>
))}
</SpringTrail>
)