• Stars
    star
    361
  • Rank 117,957 (Top 3 %)
  • Language
    JavaScript
  • Created almost 10 years ago
  • Updated over 9 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

React animation on steroid.

React State Stream

React animation on steroid. Live demo.

This is highly experimental. For a more stable and performant library, try React-motion.

Not providing a npm package for the moment.

The current master branch uses mori because there are some distinctive features I need that are not yet in immutable-js. The latter version is in the other branch and is (even more) underperformant.

What This Library Solves

General animation API, including unmounting transition (and de-unmounting!). npm install && npm run build and open index.html. There are 3 demos:

  1. Infinitely spinning child inside infinitely spinning parent.
  2. Normal tweening animation using third-party easing functions.
  3. Non-blocking unmounting and de-unmounting list.

General Concept

Instead of one state, set all the states that will ever be, aka a lazy state stream. This is akin to FRP but uses an ordinary LazySeq<State>. Also reminiscent of Flash's timeline.

A normal tween can simply be expressed as a map over a chunk of the lazy seq. Same for physics engine. Works even if the tween never stops (e.g. a physics engine where a menu item floats in mid air).

Unmounting is taken care of by storing a copy of props.children in the transition wrapper component's state stream, along with a styleConfig<childKey, Object> for animation, most probably. Each frame (componentWillUpdate) it diffs the entering/exiting children. It then describes how the transition changes:

tween = this.stream.take(100).map(state => update(state.styleConfig.childKey.height, easeOut(easeOutParams)))
rest = this.steam.drop(100)
  .map(state => update(state.config.childKey.height, 0))
  .map(state => update(state.children, blaOneLessChild))

this.stream = tween.concat(rest)

WIth this we can now do de-unmounting (ok frankly I have no idea why I'm so hooked up on this. It just feels conceptually right, you know?) by overriding the maps again.

Mentality (i.e. How This Came to Be)

One important idea is that, while the render function stays a snapshot of props and (current) state, it's called on every frame, just like in game engines. Constantly lifting every state a-la FRP sounds tedious and it's practically hard to express; but modifying a lazy seq (with an array-like API) isn't. setState(s) becomes setStateStream(InfiniteRepeat(s)).

For unmounting, we really need to treat it as first-class state stream transformation rather than some hacky afterthought. The system needs to work well when an unmounting item takes infinite time to transition out and but doesn't block anything else.

When I said first-class, I mean that we need to realize that unmounting transition is not reserved for just animation. With this library (demo 3 specifically) we gain new ways of expressing some UIs:

  • Imagine a photo app where swiping right shows the next picture. If we swipe and hold midway, there are two photos on the screen at that moment. With the transition wrapper, we don't have to take care of that logic in our main view! Picture 1 will infinitely stay in "unmounting" mode and picture 2, in "mounting" mode. In reality we've only specified one photo component in the view.
  • If we wrap the whole app in a transition wrapper, we can do portrait-landscape crossfade for free.

Thanks to this mentality (i.e. animation is really just a state stream), there are very little library-specific code here. Like, 40 lines (to change some existing React behaviors) + some general sequence helpers.

That Layout Problem

During tweening, the layout might be in an invalid state (see demo 3 where the items are moving out). I don't think it's worth the time to design a layout system that accommodates these invalid states (also remember: that invalid state might last indefinitely. See previous bullet point). Fortunately, now that we have support to do layout in JS, I'm hoping that, under the hood, it places everything in position: absolute and that we can easily read/write the values from JS. The layout problem would therefore be solved under this state stream system: the begin/end keyframes (states) are valid layouts, and you tween the values in-between by modifying the absolute position (normally discouraged but legitimate for tweening).

Optimizations

This library is not super performance currently, as I wanted to focus on the API. But there are huge perf boosts to be had. For one, I rAF setState each component so the leaf nodes get log(n) setStates per frame, lol.

One thing to be careful about is doing an infinite animation like in demo 1. Since we're mapping over an infinite lazy stream, every modification to it (that corresponds to a new map) will accumulate until that item gets evaluated. For dealing with infinite animations, we'll expose a few specific helpers in the future.

For all other terminating animations, make the stream finite. Upon reaching the last cell, the each-frame rendering will halt (so conceptually, [state] of length 1 is the same as current react state). This also conveniently puts an end to all accumulated map callback evaluations.

Laziness is important here, as are persistent collections. As long as these aren't first-class in JS, we'll have to pay the extra cost of converting collections to JS, and vice-versa (unless we use persistent collection and lazy streams in React itself). This library probably runs much faster on ClojureScript right now if I had bothered. Now we sit and wait til lazy seqs and persistent collections become JS native in 20 years.

More Repositories

1

react-motion

A spring that solves your animation problems.
JavaScript
21,680
star
2

react-tween-state

React animation.
JavaScript
1,742
star
3

react-treeview

Easy, light, flexible tree view made with React.
JavaScript
1,086
star
4

react-radio-group

Better radio buttons.
JavaScript
442
star
5

node-huxley

Codeless front-end testing.
JavaScript
365
star
6

chenglou.github.io

HTML
338
star
7

RCSS

Turn your JavaScript objects into CSS classes.
JavaScript
286
star
8

intro-to-reason-compilation

Ready up!
Shell
269
star
9

react-spinner

Zero configuration loading spinner.
JavaScript
186
star
10

tween-functions

Robert Penner's easing functions, slightly modified
JavaScript
182
star
11

data-structures

Fast, light and hassle-free JavaScript data structures, written in CoffeeScript.
JavaScript
147
star
12

pure-css-shaders-art

At the intersection of art and bad performance
HTML
121
star
13

cards

Prototyping the UI of 2030
OCaml
109
star
14

jeason

The crappy js-to-reason converter anyone can contribute to!
OCaml
106
star
15

react-chosen

React wrapper for Chosen jQuery.
HTML
96
star
16

react-dash

React documentation source for [Dash](http://kapeli.com/dash)
JavaScript
90
star
17

require-polyfill

Make `require` work in browsers, at runtime. No code bundling needed!
JavaScript
42
star
18

reason-project-ideas

40
star
19

png-diff

Small PNG diff utility, written in pure JS for Node.
JavaScript
40
star
20

react-lights-out

Simple demo of the React framework's power and flexibility.
JavaScript
27
star
21

upgrade-reason-react

OCaml
27
star
22

png-crop

Small PNG cropping utility, written in pure JS for Node.
JavaScript
23
star
23

grunt-huxley

Grunt task for node-huxley.
JavaScript
21
star
24

jon-blow-video-outlines

Outlines for Jon Blow's YouTube videos on games, programming and more.
20
star
25

multitouch-line-art

JavaScript
17
star
26

code-snippets

Code Snippets, algorithms, etc.
CoffeeScript
13
star
27

flexbox-see

Flexbox visualizer.
JavaScript
10
star
28

react-placeholder-shim

Form placeholder for input and textarea in ie8 and 9.
JavaScript
9
star
29

huxley-example

Demo from node-huxley's README
7
star
30

shaderjoy

TypeScript
6
star
31

phone-parser

Parse the phone input into an output format of your choice. Good for formatting a user input.
JavaScript
6
star
32

flappy-2048-side-by-side

An experiment in time wasting.
CSS
5
star
33

sublime-config

My configurations for Sublime Text.
JavaScript
4
star
34

the-game

yada yada
JavaScript
3
star
35

valid-css-props

Check for the validity of a CSS property name.
JavaScript
3
star
36

flip-it.safariextension

Flipboard Safari extension for adding a stuff on the web to your personal magazine.
CoffeeScript
3
star
37

l-system

Fun experiment in pattern generation, with a visualizer.
JavaScript
3
star
38

ocaml-bench

OCaml
3
star
39

bootstrap-everywhere.safariextension

Safari extension for turning websites more Californian
JavaScript
2
star
40

elastic

Something something OCaml
OCaml
2
star
41

mememe

OCaml
1
star
42

super-spy

JavaScript
1
star
43

reasonable

JavaScript
1
star
44

chalk-time

JavaScript
1
star