Giter Club home page Giter Club logo

react-tween-state's Introduction

React Tween State

The equivalent of React's this.setState, but for animated tweens: this.tweenState.

Live demo and source.

Npm:

npm install react-tween-state

Bower:

bower install react-tween-state

API

Example usage:

var tweenState = require('react-tween-state');
var React = require('react');

var App = React.createClass({
  mixins: [tweenState.Mixin],
  getInitialState: function() {
    return {left: 0};
  },
  handleClick: function() {
    this.tweenState('left', {
      easing: tweenState.easingTypes.easeInOutQuad,
      duration: 500,
      endValue: this.state.left === 0 ? 400 : 0
    });
  },
  render: function() {
    var style = {
      position: 'absolute',
      width: 50,
      height: 50,
      backgroundColor: 'lightblue',
      left: this.getTweeningValue('left')
    };
    return <div style={style} onClick={this.handleClick} />;
  }
});

The library exports Mixin, easingTypes and stackBehavior.

this.tweenState(path: String | Array<String>, configuration: Object)

This first calls setState and puts your fields straight to their final value. Under the hood, it creates a layer that interpolates from the old value to the new. You can retrieve that tweening value using getTweeningValue below.

path is the name of the state field you want to tween. If it's deeply nested, e.g. to animate c in {a: {b: {c: 1}}}, provide the path as ['a', 'b', 'c']

configuration is of the following format:

{
  easing: easingFunction,
  duration: timeInMilliseconds,
  delay: timeInMilliseconds,
  beginValue: aNumber,
  endValue: aNumber,
  onEnd: endCallback,
  stackBehavior: behaviorOption
}
  • easing (default: easingTypes.easeInOutQuad): the interpolation function used. react-tween-state provides frequently used interpolation (exposed under easingTypes). To plug in your own, the function signature is: (currentTime: Number, beginValue: Number, endValue: Number, totalDuration: Number): Number.
  • duration (default: 300).
  • delay (default: 0). *
  • beginValue (default: the current value of the state field).
  • endValue.
  • onEnd: the callback to trigger when the animation's done. **
  • stackBehavior (default: stackBehavior.ADDITIVE). Subsequent tween to the same state value will be stacked (added together). This gives a smooth tween effect that is iOS 8's new default. This blog post describes it well. The other option is stackBehavior.DESTRUCTIVE, which replaces all current animations of that state value by this new one.

* For a destructive animation, starting the next one with a delay still immediately kills the previous tween. If that's not your intention, try setTimeout or additive animation. DESTRUCTIVE + duration 0 effectively cancels all in-flight animations, skipping the easing function.

** For an additive animation, since the tweens stack and never get destroyed, the end callback is effectively fired at the end of duration.

this.getTweeningValue(path: String | Array<String>)

Get the current tweening value of the state field. Typically used in render.

License

BSD.

react-tween-state's People

Contributors

chenglou avatar icodeforlove avatar jmstout avatar magrinj avatar petehunt avatar sghiassy avatar thecontrarian avatar tn1ck avatar yunda avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-tween-state's Issues

Performance issue during Tween Animation

I found that in some cases, if I place lots of dom element in my page. Animation via tweenState can lead to performance problem. There are no obvious latency in page interaction, but it's hard to reach 50fps in iPhone4S or even iPhone5.

I suppose that every time when you execute setState in React, it will trigger the Diff process to create new ReactElement instance. If you have complex dom structure you need to generate big amount of ReactElements per frame!

I think it might cost a lot to achieve animation via setState per frame. I purpose than it is better to get the ref of the animation target ReactElement, and operate dom style directly. I know that it is not a matter of React Diff by doing so. Despite I still consider this can be the best method to achieve high performance Animation in React. I also achieve anims in my React webapp by using operate Domstyle directly.

Thank you

React 0.13 and es6 Classes

Is it possible to use react-tween-state with the new class style? Can't use mixins anymore, so what would it take for this to work?

something happen

I run the example,but: Uncaught Error: Invariant Violation: setState(...): takes an object of state variables to update.

Animate on unmount?

I'm using react-tween-state to animate components on mount, and it works great. But componentWillUnmount doesn't allow state manipulations, so the following code throws an invariant violation:

  componentWillUnmount: function() {
    this.tweenState('translateY', {
      easing: tweenState.easingTypes.easeInOutQuad,
      duration: 300,
      endValue: this.state.translateY === 100 ? 300 : 0
    });
  }

Invariant violation:

Uncaught Error: Invariant Violation: replaceState(...): Cannot update while unmounting component. This usually means you called setState() on an unmounted component.

Is the solution to this to just use react-state-stream, which handles unmounting? Trying to find an interim implementation -- one of the reasons I like react-tween-state is that animations can be defined easily as lifecycle methods, rather than wrapper components ala <CSSTransitionGroup>

Tweening functions are returning NaN

I'm having some issues with cancelling a running transition with {duration:0, stackBehavior: DESTRUCTIVE}.

After chasing it down, the problem is demonstrated by the following code:

var easeInOutQuad= function(t, b, _c, d) {
    var c = _c - b;
    if ((t /= d / 2) < 1) {
        return c / 2 * t * t + b;
    } else {
        return -c / 2 * ((--t) * (t - 2) - 1) + b;
    }
}

easeInOutQuad(0,1,1,0) // Produces NaN

isNaN(t/d) == isNaN(0/0) == true

This has a number of knock-on problems which I now have to add guards for.

Is it worth adding divide-by-zero protection to the functions?

tween while changing state to render.

I have a popup which needs to come out from bottom. popup text is dynamic and is set via state. This makes the popup height variable.

Wondering what is the right way to set the state as well as animate the popup.

Thanks for the amazing lib @chenglou ๐Ÿ‘

Looping behaviors (onEnd) and react-native

Looping behaviors seems to be broken on react-native. I tested the first example (examples/example1.jsx) which calls tweenState again each time onEnd is triggered in the browser and it's working fine.

Here a similar example for react-native: https://gist.github.com/morukutsu/c3b01e7946104f4d87af
The behavior is different:

  • tweenState is only called two times ("Called" will be printed only two times)
    The counter stops after it reached 1000.

Is there any known issue that could explain this?

I am not really sure it is a react-tween-state, react-native or another unrelated issue.

Thanks a lot !

Whole component is always re-rendered

I have animation at top "main" component. I found out that when I change property of a component that is nested inside "main", the whole "main" component is re-rendered. Besides performance, this causes problems when there is a text input field which loses focus after re-render.
Also it is strange that I had to add componentShouldUpdate to make animations work. It enables animations even when componentShouldUpdate always return true.

This can be reproduced only by adding tweenstate.Mixin without any animations enabled.
I use Om (Clojurescript), ReactJS 13.3 and react-tween-state from master.

BTW, would you recommend using chenglou/react-motion instead?

Animate arrays and objects

A rather common case for animation involves tweening more than one field together inside some nested data structure.

For instance, I am trying to port to React the demo for my library Paths.js. If you look - say - at the first chart, you will notice that when you click on a slice, it opens, while other slices close at the same time. This is done by using a vector of coefficients, which initially looks like

getInitialState: function() {
  return {
    expanded: [0, 0, 0, 0, 0]
  }
}

If you click on the second slice, it is animated to [0, 1, 0, 0, 0]. Then if you click on the fourth slice, it is animated towards [0, 0, 0, 1, 0], and so on.

In this particular case, I could fake the effect by having a fixed number of coefficients (namely 5) in the state. But I would like to write a reusable component, hence the number of slices is not known in advance.

Right now, it seems that react-tween-state works fine for animating scalar properties. It would be nice to support the animation of nested data structures. Ractive does this and makes it a breeze to write animated components

RFC: Helper function for mixin to pull out multiple tween properties

  getTweenings(propertySet) {
    if (this.state.tweenQueue.length === 0) return {};
    if (typeof propertySet === 'undefined') propertySet = [];
    var result = {};

    this.state.tweenQueue.forEach((tween) => {
      var property = tween.stateName;
      if (propertySet.length === 0 || propertySet.indexOf(property) > -1) {
        var value = this.getTweeningValue(property);
        result[property] = value;
      }
    });

    return result;
  },

Usage (with react-native):

  render() {
    return (
        <View style={[styles.container, this.getTweenings('opacity')]}>
           <View style={[styles.content, this.getTweenings(['left', 'top'])}>
           </View>
        </View>
    );
  }

Or if you just want to grab all of the properties:

  render() {
    return (
        <View style={[styles.container, this.getTweenings()]}>
        </View>
    );
  }

Tween strings?

In some cases strings need to be tweened e.g. rgb or path strings. It seems I would have to override the _getTweeningValue function.

Add delay option

This looks really cool and useful, but would really benefit from a delay option. Currently for us to use it as we intend, we'd have to wrap it in a setTimeout() everywhere.

tweening multiple values?

Say I want to animate some div from:

transform: translate3d(-100%,0px,0px);
opacity: 0.0

to

transform: translate3d(0%,0px,0px);
opacity: 1.0

and I want them in perfect sync.

Will two consecutive calls to this.tweenState() with the same duration accomplish this? Or is there some other way which I overlooked?

If not, I'll be happy to try a PR with this kind of "batch" support.

Default export is missing

I seems as there is no export default ... causing the module to be empty.

I had to explicit pick the Mixin (import { Mixin as tweenStateMixin } from 'react-tween-state') instead of loading the full module (import tweenState from 'react-tween-state')

request: ES6 class and not mixin

Is this module in active development?

React.createClass will be deprecated and removed in one of the next releases. This makes Mixins go away.

Have you considered re-writing as an extendable ES6 class component?

React-Native example problem

I'm trying to make some simple example for react native.

'use strict';

var React = require('react-native');
var {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  TouchableWithoutFeedback,
} = React;

var tweenState = require('react-tween-state');

var NewAnim = React.createClass({
  //mixins: [tweenState.Mixin],

  getInitialState() {
    return { opacity: 1 }
  },

  _animateOpacity() {
    // this.tweenState('opacity', {
    //   easing: tweenState.easingTypes.easeOutQuint,
    //   duration: 1000,
    //   endValue: this.state.opacity === 0.2 ? 1 : 0.2,
    // });
  },

  render() {
    return (
      <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
        <TouchableWithoutFeedback onPress={this._animateOpacity}>
          <View ref={component => this._box = component}
                style={{width: 200, height: 200, backgroundColor: 'red',
                        }} />
        </TouchableWithoutFeedback>
      </View>
    )
  },
});


AppRegistry.registerComponent('NewAnim', () => NewAnim)

module.exports = NewAnim;

I've tried to comment out all functionality and determine place where error appears. Now I see that it appears when line with

var tweenState = require('react-tween-state');

becomes uncommented

API change for the first parameter?

Instead of tweenState(function(state) {return state.a.b;}, config), maybe it's nicer to have tweenState(['a', 'b'], config) instead.

Pros: more idiomatic to immutable-js/mori. Shorter and probably slightly more intuitive. getTweeningValue looks much nicer.
Cons: not google closure advanced compilation mode compatible. Less type-checkable? Does anyone care?

Will leave this here and consider it. Don't wanna randomly break the API.

Is this usable with react-native

It is confusing that the official docs state "Not recommended" and then precede to give an example of it usage.

I tried using it and found that it did not behave well with react-native. Does this play nice with react-native, or is it also "Not recommended" by you for use with react-native. Actually similar question for react-motion.

best regards,

clone tween options

Currently passing the same object to two this.tweenStates causes them to mess with eachother.

Error when onEnd removed component tweening state

This should probably work:

      this.tweenState('step', {
        endValue: 2,
        duration: this.props.animationDuration,
        onEnd: this.props.onClose
      });

But if props.onClose removes the tweening element I get an error setState on non-mounted component. This fixes it for now:

      this.tweenState('step', {
        endValue: 2,
        duration: this.props.animationDuration,
        onEnd: () => {
          setTimeout(this.props.onClose);
        }
     });

Not working on 0.13 beta1

Just updated and my tweenState on componentDidMount seems to have broken, though not on willUnmount.

What should I do when I need to change more than one states at the same time?

In my case.

   getInitialState: function() {
        return {
            visible: this.props.visible,
            height: -1,
        };
    },

I need the tween to change the height, meanwhile changing the visible too.
But I don't want the react refresh the dom twice in this case.
Now I just use the anti-pattern way.
this.state.visible = !this.state.visible

Generalizing the easing timing function?

Hi,

I don't think you remember me but we quickly met on React Europe but we didn't talk much, there was lot of people ;)

Anyway..

I'm the author of bezier-easing that solves a simple problem: implementing the cubic bezier easing in JavaScript (like the one available in CSS Transitions).
It basically would allow react-tween-state to move from a limited set of primitive easings to infinite number of (cubic) easings.

That's quite simple to use:

var easing = BezierEasing(0, 0, 1, 0.5);
console.log(easing.get(0.5)); // 0.3125

I really like the idea to make bricks out of micro libraries :) Because every tiny library can focus on performance (which is the case of bezier-easing, it is based on efficient firefox implementation).

Do you think this could make sense to generalise the easing part of react-tween-state with that approach?

Thanks

PS: This micro library is being used by Apple.com for a few years as part of their animation library in product pages, and is also used in velocity.js.

Presentation layer might not work well with shouldComponentUpdate

We basically hide a new state for the transitioning values so manual comparisons in shouldComponentUpdate (without considering the hidden state) would return the bad result during transition (aka not updating when we need to update). Wouldn't be a problem with a deepCompare(state1, state2) function, except js doesn't have it by default so people don't do that.

Tween props between renders

So say I have a component which is displaying a number being passed down as a prop from a parent component. When that prop changes and the component re-renders, I'd like to animate that number incrementing to the new prop value (and using easing to decelerate the increment speed as it approaches the new value).

This doesn't seem possible with this currently, as moving the prop to the child component's state decouples it from being updated.

There aren't any other existing solutions that I've found so far, and this repo gives everything I'd want... except that it won't work on props... Is there a way support for props might be added?

Question: Multiple simultaneous transitions

One of my main problems with CSSTransitionGroup is that it doesn't handle simultaneous transitions.

ie ...transition: left .2s ease-in-out, top .5s ease-in-out...

I suppose this takes care of it?

 this.tweenState('left', {
      easing: tweenState.easingTypes.easeInOutQuad,
      duration: 200,
      endValue: 100
 });
 this.tweenState('top', {
      easing: tweenState.easingTypes.easeInOutQuad,
      duration: 500,
      endValue: 200,
      onEnd: endCallback
 })

onEnd callback fires way too soon.

The onEnd callback fires way before the actual tween end. This is really obvious when you set a duration around > 2 seconds, the callback seems to fire almost instantly. Adding any delay also makes no difference to when this callback fires.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.