A spring that solves your animation problems.
import {Motion, spring} from 'react-motion'; // In your render... {value =>{value.x}}
Animate a counter from
0to
10. For more advanced usage, see below.
Npm:
npm install --save react-motion
Bower: do not install with
bower install react-motion, it won't work. Use
bower install --save https://unpkg.com/react-motion/bower.zip. Or in
bower.json:
json { "dependencies": { "react-motion": "https://unpkg.com/react-motion/bower.zip" } }then include as
html
1998 Script Tag:
html (Module exposed as `ReactMotion`)
Works with React-Native v0.18+.
git clone https://github.com/chenglou/react-motion.git cd react-motion npm install
npm start.
npm run build-demosand open the static
demos/demo_name/index.htmlfile directly. Don't forget to use production mode when testing your animation's performance!
To build the repo yourself:
npm run prepublish.
For 95% of use-cases of animating components, we don't have to resort to using hard-coded easing curves and duration. Set up a stiffness and damping for your UI element, and let the magic of physics take care of the rest. This way, you don't have to worry about petty situations such as interrupted animation behavior. It also greatly simplifies the API.
This library also provides an alternative, more powerful API for React's
TransitionGroup.
Exports: -
spring-
Motion-
StaggeredMotion-
TransitionMotion-
presets
Here's the well-annotated public Flow type definition file (you don't have to use Flow with React-motion, but the types help document the API below).
P.S. using TypeScript? Here are the React-motion TypeScript definitions!
Used in conjunction with the components below. Specifies the how to animate to the destination value, e.g.
spring(10, {stiffness: 120, damping: 17})means "animate to value 10, with a spring of stiffness 120 and damping 17".
val: the value.
config: optional, for further adjustments. Possible fields:
stiffness: optional, defaults to
170.
damping: optional, defaults to
26.
precision: optional, defaults to
0.01. Specifies both the rounding of the interpolated value and the speed (internal).
It's normal not to feel how stiffness and damping affect your spring; use Spring Parameters Chooser to get a feeling. Usually, you'd just use the list of tasteful stiffness/damping presets below.
{stiffness, damping}
Commonly used spring configurations used like so:
spring(10, presets.wobbly)or
spring(20, {...presets.gentle, precision: 0.1}). See here.
{interpolatingStyle => }
Required. The
Styletype is an object that maps to either a
numberor an
OpaqueConfigreturned by
spring()above. Must keep the same keys throughout component's existence. The meaning of the values:
OpaqueConfigreturned from
spring(x): interpolate to
x.
number
x: jump to
x, do not interpolate.
Optional. The
PlainStyletype maps to
numbers. Defaults to an object with the same keys as
styleabove, whose values are the initial numbers you're interpolating on. Note that during subsequent renders, this prop is ignored. The values will interpolate from the current ones to the destination ones (specified by
style).
Required function.
interpolatedStyle: the interpolated style object passed back to you. E.g. if you gave
style={{x: spring(10), y: spring(20)}}, you'll receive as
interpolatedStyle, at a certain time,
{x: 5.2, y: 12.1}, which you can then apply on your
divor something else.
Return: must return one React element to render.
Optional. The callback that fires when the animation comes to a rest.
Animates a collection of (fixed length) items whose values depend on each other, creating a natural, springy, "staggering" effect like so. This is preferred over hard-coding a delay for an array of
Motionsto achieve a similar (but less natural-looking) effect.
prevInterpolatedStyles.map((_, i) => { return i === 0 ? {h: spring(100)} : {h: spring(prevInterpolatedStyles[i - 1].h)} })}> {interpolatingStyles =>{interpolatingStyles.map((style, i) => ) }}
Aka "the current spring's destination value is the interpolating value of the previous spring". Imagine a spring dragging another. Physics, it works!
Required function. Don't forget the "s"!
previousInterpolatedStyles: the previously interpolating (array of) styles (
undefinedat first render, unless
defaultStylesis provided).
Return: must return an array of
Styles containing the destination values, e.g.
[{x: spring(10)}, {x: spring(20)}].
Optional. Similar to
Motion's
defaultStyle, but an array of them.
Required function. Similar to
Motion's
children, but accepts the array of interpolated styles instead, e.g.
[{x: 5}, {x: 6.4}, {x: 8.1}]
(No
onRestfor StaggeredMotion because we haven't found a good semantics for it yet. Voice your support in the issues section.)
Helps you to do mounting and unmounting animation.
You have items
a,
b,
c, with their respective style configuration, given to
TransitionMotion's
styles. In its
childrenfunction, you're passed the three interpolated styles as params; you map over them and produce three components. All is good.
During next render, you give only
aand
b, indicating that you want
cgone, but that you'd like to animate it reaching value
0, before killing it for good.
Fortunately,
TransitionMotionhas kept
caround and still passes it into the
childrenfunction param. So when you're mapping over these three interpolated styles, you're still producing three components. It'll keep interpolating, while checking
c's current value at every frame. Once
creaches the specified
0,
TransitionMotionwill remove it for good (from the interpolated styles passed to your
childrenfunction).
This time, when mapping through the two remaining interpolated styles, you'll produce only two components.
cis gone for real.
import createReactClass from 'create-react-class';const Demo = createReactClass({ getInitialState() { return { items: [{key: 'a', size: 10}, {key: 'b', size: 20}, {key: 'c', size: 30}], }; }, componentDidMount() { this.setState({ items: [{key: 'a', size: 10}, {key: 'b', size: 20}], // remove c. }); }, willLeave() { // triggered when c's gone. Keeping c until its width/height reach 0. return {width: spring(0), height: spring(0)}; }, render() { return ( ({ key: item.key, style: {width: item.size, height: item.size}, }))}> {interpolatedStyles => // first render: a, b, c. Second: still a, b, c! Only last one's a, b.
{interpolatedStyles.map(config => { return })}} ); }, });
First, two type definitions to ease the comprehension.
TransitionStyle: an object of the format
{key: string, data?: any, style: Style}.
key: required. The ID that
TransitionMotionuses to track which configuration is which across renders, even when things are reordered. Typically reused as the component
keywhen you map over the interpolated styles.
data: optional. Anything you'd like to carry along. This is so that when the previous section example's
cdisappears, you still get to access
c's related data, such as the text to display along with it.
style: required. The actual starting style configuration, similar to what you provide for
Motion's
style. Maps keys to either a number or an
OpaqueConfigreturned by
spring().
TransitionPlainStyle: similar to above, except the
stylefield's value is of type
PlainStyle, aka an object that maps to numbers.
Required. Accepts either:
an array of
TransitionStyleconfigs, e.g.
[{key: 'a', style: {x: spring(0)}}, {key: 'b', style: {x: spring(10)}}].
a function similar to
StaggeredMotion, taking the previously interpolating styles (
undefinedat first call, unless
defaultStylesis provided), and returning the previously mentioned array of configs. You can do staggered mounting animation with this.
Optional. Similar to the other components'
defaultStyle/
defaultStyles.
Required function. Similar to other two components'
children. Receive back an array similar to what you provided for
defaultStyles, only that each
styleobject's number value represent the currently interpolating value.
Optional. Defaults to
() => null. The magic sauce property.
styleThatLeft: the e.g.
{key: ..., data: ..., style: ...}object from the
stylesarray, identified by
key, that was present during a previous render, and that is now absent, thus triggering the call to
willLeave. Note that the style property is exactly what you passed in
styles, and is not interpolated. For example, if you passed a spring for
xyou will receive an object like
{x: {stiffness, damping, val, precision}}.
Return:
nullto indicate you want the
TransitionStylegone immediately. A
Styleobject to indicate you want to reach transition to the specified value(s) before killing the
TransitionStyle.
{key: string, data?: any}) => void
Optional. Defaults to
() => {}.
styleThatLeft: the
{key:..., data:...}that was removed after the finished transition.
Optional. Defaults to
styleThatEntered => stripStyle(styleThatEntered.style). Where
stripStyleturns
{x: spring(10), y: spring(20)}into
{x: 10, y: 20}.
styleThatEntered: similar to
willLeave's, except the
TransitionStylerepresents the object whose
keyvalue was absent during the last
render, and that is now present.
Return: a
defaultStyle-like
PlainStyleconfiguration, e.g.
{x: 0, y: 0}, that serves as the starting values of the animation. Under this light, the default provided means "a style config that has the same starting values as the destination values".
Note that
willEnterand
defaultStylesserve different purposes.
willEnteronly triggers when a previously inexistent
TransitionStyleinside
stylescomes into the new render.
(No
onRestfor TransitionMotion because we haven't found a good semantics for it yet. Voice your support in the issues section.)
Hard-coded duration goes against fluid interfaces. If your animation is interrupted mid-way, you'd get a weird completion animation if you hard-coded the time. That being said, in the demo section there's a great Spring Parameters Chooser for you to have a feel of what spring is appropriate, rather than guessing a duration in the dark.
TransitionMotioncontainer itself?
You don't. Unless you put it in another
TransitionMotion...
StaggeredMotion
refdoesn't work in the children function.
React string refs won't work:
{currentValue => }
This is how React works. Here's the callback ref solution.