Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

State changes that don't happen through tweens can break them #3

Open
lettertwo opened this issue Jul 16, 2014 · 2 comments
Open

State changes that don't happen through tweens can break them #3

lettertwo opened this issue Jul 16, 2014 · 2 comments

Comments

@lettertwo
Copy link
Contributor

Because state changes in React components can be asynchronous, the plugin has to track a proxy for the component state so that multiple tweens can act in between component updates.

But, because the component doesn't know about this proxy, there is no way for the tweens to know when the state is changed outside of the tweening process. For example:

React.createClass({
  getInitialState: function() {
    return {x: 0}
  },
  componentDidMount: function() {
    // Tween state.x from the initial value of 0 to 100.
    // When that tween completes, set the state back to 0.
    TweenLite
      .to(this, 0.5, {state: {x: 100}})
      .addCallback('onComplete', function(){
        this.setState({x: 0});
      }.bind(this));
  },
  componentDidUpdate: function() {
    // You would expect this to tween to 100 starting from 0, since the state
    // was updated in the 'onComplete' callback in `componentDidMount`, but it
    // doesn't because the internal plugin proxy doesn't know the state changed!
    TweenLite
      .to(this, 0.5, {state: {x: 100}});
  },
  render: function() { /* etc... */ }
});

There doesn't seem to be any good options for solving this.

Here are some bad ones:

  1. mutate target.state directly (instead of maintaining an separate tween state and binding them together)
    • bad because it will cause issues for componentShouldUpdate and componentDidUpdate, when comparisons between previous and next tween states are inaccurate (since the state gets mutated directly between renders by the tween)
  2. override target.setState to make sure it also updates the tween state
    • this just seems evil
  3. add a setTweenState method to the component that can update the tween proxy object and call setState
    • this means your component has to use this special method everywhere that it would normally use setState (or at least everywhere that the component would want to update state that is also being tweened)
    • might be the best option?
@lettertwo
Copy link
Contributor Author

Maybe we can circumvent the issue by inspecting the tween instance when the plugin initializes, and look for the immediateRender flag. If it's present, we pull the start values from component.state instead of tweenState.

lettertwo added a commit that referenced this issue Jul 17, 2014
Previously, all tweens shared a tween state which was bound to the target
component. Now, every tween maintains its own state internally, and merely
initializes its state based on the shared state (giving priority to the actual
component state).

I think this addresses GH-3, but I guess we'll need a bit more real world testing
to know for sure.
lettertwo added a commit that referenced this issue Jul 17, 2014
Previously, all tweens shared a tween state which was bound to the target
component. Now, every tween maintains its own state internally, and merely
initializes its state based on the shared state (giving priority to the actual
component state).

I think this addresses GH-3, but I guess we'll need a bit more real world
testing to know for sure.
@lettertwo
Copy link
Contributor Author

Just published v1.0.2 which might be a workable solution to this problem. I guess we'll have to wait and see...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant