Skip to content

Instantly share code, notes, and snippets.

@natew
Last active August 29, 2015 14:18
Show Gist options
  • Save natew/f0c396442584b071915f to your computer and use it in GitHub Desktop.
Save natew/f0c396442584b071915f to your computer and use it in GitHub Desktop.
Nested animations through context in Reapp
<ViewList animator> // passes context: { step: 0.555 }
<View /> // extends context with { index: 0 }
<View /> // ...
<View> // extends context with { index: 2 }
// here's the tricky part: you can nest ViewLists, and they should pass their "new" context down to their children
<ViewList> // reset context { step: 0 }
<View /> // reset context { index: 0 }
</ViewList>
</View>
</ViewList>
Where a View has nested animations:
<View> // animates inner view
<TitleBar> // animates slower than view
<Button>
<Icon animated> // animates against titlebar to stay in same place
</Button>
</TitleBar>
</View>
@natew
Copy link
Author

natew commented Apr 9, 2015

To see an example of this, go to: http://kitchen.reapp.io/

And go into Nested View Lists demo (Or Dotted). Notice they are inside a viewlist already.

@natew
Copy link
Author

natew commented Apr 9, 2015

Whats actually passed down from ViewList:

animations: {
  viewList: {
    step: number
  }
}

Then from View extends that

animations: {
  viewList: {
    step: number,
    index: number,
    width: number,
    height: number
  }
}

@natew
Copy link
Author

natew commented Apr 9, 2015

With observable, I guess it would be:

ViewList

animations: { viewList: Observable }}

View would then need to push extra stuff onto the observable in it's own context tree. I'm actually struggling more with performance so if this would help avoid re-render on ViewList would be a big win.

@andreypopp
Copy link

So the requirements as I understand:

  • You need to push animation state updates to components which are interested in them
  • You want to avoid re-renders of components which are not interested in animation state updates
  • You want to configure animation state transformations based on component tree configuration

What I propose is to configure observable graph in getChildContext of components.

The top level one would have:

getChildContext() {
  return {animation: this.animationObservable}
}

Some children can override observables by transforming current one from own context (shift in time for example):

getChildContext() {
  return {animation: this.context.animation.map(x => {...x, step: x.step + 100})}
}

Another children who perform animations would subscribe to observable and re-render themselves when new value is available:

componentWillMount() {
  this.context.subscribe((animationState) => {
    this.setState({animationState}) // now render is called and we can use this.state.animationState to influence DOM
  })
}

.

That basically means that we use context only to configure "pipes" for animation state, how it flows through component hierarchy.

Now to push new animationState we get some component and provide new values to its animation observable:

component.animationObservable.onNext({step: 0, ...})

That way we don't re-render components unless they subscribe to animationState from context. But at the same time we don't need getChildContext to be called because animationState-propagation graph already configured and is static.

Some unanswered questions are... what to do when we unmount/remount some components when animation is in progress? The animation graph could be reconfigured in this case (because getChildContext of some components will be called again) and it can influence animation in some way, for example we can get some jumps in animation and so on. But I think this is a general problem, not specific to proposed setup.

@andreypopp
Copy link

As I understand index reflects component hierarchy configuration in some way, it should be outside of observable in this case, I think. If step is the one which is dynamic (time?) it should be an observable.

@natew
Copy link
Author

natew commented Apr 10, 2015

@andreypopp as for you concerns with unmount, I've run into this at least in one case, but it's actually not been bad. I do have a component called AnimationLoop and you could extend that type of component to keep it's children in state, etc.

Thanks for the thoughts here. Glad I started looking into this. I'm super busy at the moment but you can see the code diff here:

https://github.com/reapp/reapp-ui/compare/observeAnimations

It needs lots of bugfixing and optimization though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment