GithubHelp home page GithubHelp logo

react-state-stream's Introduction

React State Stream

React animation on steroid. Live demo.

This is highly experimental. For a more stable and performant library, try React Tween State.

Not providing a npm package for the moment. Actively looking for feedback since this might as well be the default React animation mechanism in the future.

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 watch and open http://localhost:3000/. 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 = => 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)) = 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).


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.

react-state-stream's People


chenglou avatar gaearon avatar kyleamathews avatar


 avatar  avatar  avatar  avatar  avatar  avatar


 avatar  avatar



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.