react-motion README

The project's README from github.com/chenglou/react-motion. As one markdown file: README.md.

React-Motion

Build Status npm version Bower version react-motion channel on discord

import {Motion, spring} from 'react-motion';
// In your render...
<Motion defaultStyle={{x: 0}} style={{x: spring(10)}}>
  {value => <div>{value.x}</div>}
</Motion>

Animate a counter from 0 to 10. For more advanced usage, see below.

Install

{
  "dependencies": {
    "react-motion": "https://unpkg.com/react-motion/bower.zip"
  }
}

then include as

<script src="bower_components/react-motion/build/react-motion.js"></script>
<script src="https://unpkg.com/react-motion/build/react-motion.js"></script>
(Module exposed as `ReactMotion`)

Works with React-Native v0.18+.

Demos

Check the wiki for more!

Try the Demos Locally

git clone https://github.com/chenglou/react-motion.git
cd react-motion
npm install

To build the repo yourself: npm run prepublish.

What does this library try to solve?

My React-Europe talk

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.

API

Exports:

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!


Helpers

- spring: (val: number, config?: SpringHelperConfig) => OpaqueConfig

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".

- Presets for {stiffness, damping}

Commonly used spring configurations used like so: spring(10, presets.wobbly) or spring(20, {...presets.gentle, precision: 0.1}). See here.


<Motion />

Usage

<Motion defaultStyle={{x: 0}} style={{x: spring(10)}}>
  {interpolatingStyle => <div style={interpolatingStyle} />}
</Motion>

Props

- style: Style

Required. The Style type is an object that maps to either a number or an OpaqueConfig returned by spring() above. Must keep the same keys throughout component's existence. The meaning of the values:

- defaultStyle?: PlainStyle

Optional. The PlainStyle type maps to numbers. Defaults to an object with the same keys as style above, 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).

- children: (interpolatedStyle: PlainStyle) => ReactElement

Required function.

- onRest?: () => void

Optional. The callback that fires when the animation comes to a rest.


<StaggeredMotion />

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 Motions to achieve a similar (but less natural-looking) effect.

Usage

<StaggeredMotion
  defaultStyles={[{h: 0}, {h: 0}, {h: 0}]}
  styles={prevInterpolatedStyles => prevInterpolatedStyles.map((_, i) => {
    return i === 0
      ? {h: spring(100)}
      : {h: spring(prevInterpolatedStyles[i - 1].h)}
  })}>
  {interpolatingStyles =>
    <div>
      {interpolatingStyles.map((style, i) =>
        <div key={i} style={{border: '1px solid', height: style.h}} />)
      }
    </div>
  }
</StaggeredMotion>

Aka "the current spring's destination value is the interpolating value of the previous spring". Imagine a spring dragging another. Physics, it works!

Props

- styles: (previousInterpolatedStyles: ?Array<PlainStyle>) => Array<Style>

Required function. Don't forget the "s"!

- defaultStyles?: Array<PlainStyle>

Optional. Similar to Motion's defaultStyle, but an array of them.

- children: (interpolatedStyles: Array<PlainStyle>) => ReactElement

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 onRest for StaggeredMotion because we haven't found a good semantics for it yet. Voice your support in the issues section.)


<TransitionMotion />

Helps you to do mounting and unmounting animation.

Usage

You have items a, b, c, with their respective style configuration, given to TransitionMotion's styles. In its children function, 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 a and b, indicating that you want c gone, but that you'd like to animate it reaching value 0, before killing it for good.

Fortunately, TransitionMotion has kept c around and still passes it into the children function 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 c reaches the specified 0, TransitionMotion will remove it for good (from the interpolated styles passed to your children function).

This time, when mapping through the two remaining interpolated styles, you'll produce only two components. c is 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 (
      <TransitionMotion
        willLeave={this.willLeave}
        styles={this.state.items.map(item => ({
          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.
          <div>
            {interpolatedStyles.map(config => {
              return <div key={config.key} style={{...config.style, border: '1px solid'}} />
            })}
          </div>
        }
      </TransitionMotion>
    );
  },
});

Props

First, two type definitions to ease the comprehension.

- styles: Array<TransitionStyle> | (previousInterpolatedStyles: ?Array<TransitionPlainStyle>) => Array<TransitionStyle>

Required. Accepts either:

- defaultStyles?: Array<TransitionPlainStyle>

Optional. Similar to the other components' defaultStyle/defaultStyles.

- children: (interpolatedStyles: Array<TransitionPlainStyle>) => ReactElement

Required function. Similar to other two components' children. Receive back an array similar to what you provided for defaultStyles, only that each style object's number value represent the currently interpolating value.

- willLeave?: (styleThatLeft: TransitionStyle) => ?Style

Optional. Defaults to () => null. The magic sauce property.

- didLeave?: (styleThatLeft: {key: string, data?: any}) => void

Optional. Defaults to () => {}.

- willEnter?: (styleThatEntered: TransitionStyle) => PlainStyle

Optional. Defaults to styleThatEntered => stripStyle(styleThatEntered.style). Where stripStyle turns {x: spring(10), y: spring(20)} into {x: 10, y: 20}.

Note that willEnter and defaultStyles serve different purposes. willEnter only triggers when a previously inexistent TransitionStyle inside styles comes into the new render.

(No onRest for TransitionMotion because we haven't found a good semantics for it yet. Voice your support in the issues section.)


FAQ

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.

You don't. Unless you put it in another TransitionMotion...

See StaggeredMotion

React string refs won't work:

<Motion style={...}>{currentValue => <div ref="stuff" />}</Motion>

This is how React works. Here's the callback ref solution.

react-motion (chenglou/react-motion)

Searching Database…

这是什么?react-motion 是一个 React 动画库,它用弹簧物理模型来驱动组件动画,而不是依赖写死的时长和缓动曲线。
这是框架还是库?它是一个库,你需要把它导入到 React 应用中使用。它导出的组件和工具包括 spring、Motion、StaggeredMotion、TransitionMotion 以及 presets。
我该怎么把它加到项目里?先用 npm install --save react-motion 安装,然后在 Motion、StaggeredMotion 或 TransitionMotion 组件中,用 spring() 把你想做动画的数值包起来。
安装它需要 Bower 或其他什么特殊工具吗?不需要,推荐使用 npm;README 明确提醒不要使用 Bower。
我该怎么控制动画的速度或时长?没有时长设置。你需要在 spring 上调整 stiffness 和 damping(默认值分别为 170 和 26),也可以使用自带的 Spring Parameters Chooser 演示,找到手感合适的数值。
这只能用在 Web 端的 React 中,还是也支持 React Native?同时支持 React Native,具体要求是 0.18 及以上版本;也支持通过 npm 或 script 标签使用的普通 Web 端 React。
StaggeredMotion 是用来做什么的?它用于对长度固定的一组元素做动画,其中每个元素的弹簧数值都依赖前一个元素,从而形成自然的错落效果,而不是依靠写死的延迟。
TransitionMotion 有什么用?它用于处理元素挂载和卸载时的动画,会先保留这些元素(例如将其动画过渡到 0),再通过 willLeave 和 willEnter 回调将它们彻底移除。
有可以直接用的弹簧配置预设吗?有。该库内置了 wobbly、gentle 等命名预设,可以这样使用:spring(10, presets.wobbly)。
为什么不直接写死动画时长?写死的时长在动画中途被打断时会出问题,会产生奇怪的收尾动画;基于物理的弹簧则能自然地处理被打断的情况。
Creator
chenglou
Size
5.2 MB
Stars
21.9K
Age
11y
Commits · 90 Days