Hacker News new | past | comments | ask | show | jobs | submit login
Redux: Atomic Flux with Hot Reloading (github.com/gaearon)
186 points by monort on July 5, 2015 | hide | past | favorite | 44 comments

Redux is a major improvement over Flux libraries because it removes a lot of boilerplate while not removing functionality (in fact, enabling more features). In Flux libraries, it's common for an entity to take inputs and simply produce outputs. That's not the use case for a class. It's the use case for a function, and that's why Redux removes boilerplate.

However, I think it's time we stop calling everything Flux. Just because an architecture is unidirectional doesn't mean it's Flux. Facebook described it clearly as an architecture structured with: Dispatcher, Stores, Actions, Action Creators, and Components (sometimes even with the distinction of View and Controller View). Redux is Flux-inspired, but has significant differences. Maybe we should call it just Flux-inspired architecture. The distinction is important because there are other unidirectional data flow architectures such as in Elm (https://github.com/evancz/elm-architecture-tutorial) and Cycle.js (http://cycle.js.org). We might be creating confusion when mentioning "Flux" and meaning different things.

I think you are right. It's time we give a proper name to these unidirectional data flow architectures and fly away from the Flux naming.

Once terminology gets momentum it's hard to change it, it's usually not totally semantically meaningful (socket?!), but it's nice to have a convention. I think isomorphic JS is a ridiculous term, but at least there's a word for it.

I've been using capitalization to denote the difference, just like Agile vs agile: Facebook's Flux or an implementation of the Flux architecture, versus a flux architecture.

Why is the term isomorphic so 'ridiculous'?

I've read Michael Jackson's article and I didn't interpret it as saying that people using the term isomorphic are outright wrong. Some people are making this assertion and that is what I am trying to refute here.

I disagree with Michael's statement that two things that are the same cannot be isomorphic. The very definition he cites does not exclude the possibly of those things being the same!

   "Corresponding or in similar form or relations"
(Even in mathematics the identity function is an isomorphism, it follows from its definition. However, we are not trying to prove a mathematical property here.)

But even then the assertion that the server and client side are exactly identical is not correct. Typically such code bases will have slightly different entry points for server and client. Additionally, React 0.14 beta is now splitting the DOM and String renders.

For some 'Universal' is attractive, because they want to use Javascript everywhere. I get that. If you like that, please go ahead and call it 'Universal'.

However, what matters equally is having an abstraction which allows pure functions to declaratively describe the form of components based on immutable data, no matter what the computational model of the target. It is arguably the abstraction that is the isomorphism and code that uses it could be called isomorphic. That could be stretching the term as per the above definition, but that doesn't mean that people who use it are wrong.

I think React provides the necessary abstraction. I have total respect for what the React core team and the community have achieved. I understand that Michael Jackson and Ryan Florence are motivated by wanting to get more people using React. This is a very good thing.

However, other people may be more interested in promoting the ideas behind React rather than React or Javascript specifically. It is these people I am trying to defend.

The term "isomorphic JavaScript" also sounds strange to my ears. I think it’s because in traditional use (in mathematics, linguistics, biology, etc.) you don't say "X is isomorphic", you say that "X and Y are isomorphic".

Grammatically, it’s kind of like the word "similar". I would feel silly saying "JavaScript is a similar language", and I feel equally silly saying "JavaScript is an isomorphic language". Similar/isomorphic to what?

"Server-side JS rendering" and "universal" (also known as the old "write once, run everywhere"). No other term needed, as far as I can see.

By the way, with regard to isomorphic JS: https://medium.com/@mjackson/universal-javascript-4761051b7a...

Here's the video about it from React Europe: https://www.youtube.com/watch?v=xsSnOQynTHs

And if you like Dan's talk, check out his blog post My Inspiration to get some more background on the topic. https://medium.com/@dan_abramov/my-inspiration-ce454ab65f33

BTW vjeux, great job at React Europe!

One of my favorite talks I've seen. Highly recommended.

This is pretty much elm (http://elm-lang.org) and elm architecture (https://github.com/evancz/elm-architecture-tutorial/)

Yes, and you can find them in "Inspiration" section and the end of the README.

Where did the idea of (db action) => db come from? A reduction?

The hardest part of learning React is trying to figure out which incarnation of flux one should use.

The dirty secret is: they're probably all fine.

It's unlikely that you will choose a flux lib that will be the make or break point of your application.

Even if a library stops being "maintained", most decent flux incarnations are really small (~100 LoC) - it's unlikely that there's some fatal flaw you'll be stuck with.

In summary: redux is neat, but don't beat yourself up over choosing the perfect flux lib - just grab one that you like the look of and move on with building your application.

this is a great point. Also, since the overall architecture is going to be similar no matter which one you use, it's likely not going to be a major hassle to switch to a different one later.

I really hope NuclearJS (by optimizely) wins out. It shares the "pure function" philosophy of Redux, along with use of Immutable.JS and a really powerful notion of functional data transforms/lenses called 'getters'.

Docs are incomplete:


Redux doesn't care what you use for state, so you may (or may not) use ImmutableJS too.

Here's an example of the “getters” concept with Redux: https://github.com/faassen/reselect. (Sorry, no README yet :-( ). They don't have to be inside the core.

I actually like Reflux https://github.com/spoike/refluxjs

It's not "Pure" Flux, which is the reason I like it, it doesn't deal with a Dispatcher and it has syntactic sugar for 'common' use-cases, most Rails dev enjoy stuff like that.

Seems like Reflux can't have hot-reloading because there is no (public?) dispatcher to replay values :-/

I wouldn't really recommend Reflux. What advantages it has are shared by other, better libraries like alt or redux, but it has some disadvantages all its own.

Ran across a good writeup here: https://www.reddit.com/r/javascript/comments/3ap0y6/flux_no_...

I am really enjoying Reflux personally and I think that's one of the good things about React and the Fluxes; there's many mental models to suit different ways of thinking about how to build apps.

There is no 100% correct way to build complex single page web apps but there is definitely a wrong way and that way looks increasing like progressive enhancement sadly...

I agree.

I am currently in the early stages of starting a project and I want to use react+flux. However with the different variants of flux finding the one that is the best fit and is going to be maintained a year from now isn't an easy task. I think I might end up using the facebook variant as I'm fairly certain that they will continue to maintain it.

It's good practice to write your own Flux implementation for any new React project. It's pretty straightforward; just a few hundred lines of JavaScript.

I'm using alt.js[1] at now (very good implementation without boilerplate such switch/cases), but waiting Redux 1.0.

[1] http://alt.js.org

They all boil down to the same thing. I use this one https://github.com/acdlite/flummox minimum boilerplate

Further boilerplate reduction: https://gist.github.com/patio11/b472ccb2df3e1fcce78c I was going crazy with all the sit-ups to hook actions/stores together prior to this.

Heh I know exactly what you mean. Just 3 hours ago I was thinking about rewriting it, but 4 actions and 4 stores don't justify it. Thanks for sharing.

For the reader. This starts to grow quite quickly.

    import SearchActions from './actions/searchActions.js';
    import VideoActions from './actions/videoActions.js';
    import VideoMetaActions from './actions/videoMetaActions.js';
    import MusicPlayerActions from './actions/musicPlayerActions.js';
    import SearchStore from './stores/searchStore.js';
    import VideoStore from './stores/videoStore.js';
    import VideoMetaStore from './stores/videoMetaStore.js';
    import MusicPlayerStore from './stores/musicPlayerStore.js';
    class Flux extends Flummox {
      constructor() {
        this.createActions('search', SearchActions);
        this.createStore('search', SearchStore, this);
        this.createActions('video', VideoActions);
        this.createStore('video', VideoStore, this);
        this.createActions('videoMeta', VideoMetaActions);
        this.createStore('videoMeta', VideoMetaStore, this);
        this.createActions('musicPlayer', MusicPlayerActions);
        this.createStore('musicPlayer', MusicPlayerStore, this);
What is more, store registration could be improved as well

    const videoMetaActions = flux.getActions('videoMeta');
    this.register(videoMetaActions.setAudioVolume, this.handleAudioVolume);
    this.register(videoMetaActions.setMusicVolume, this.handleMusicVolume);
    this.register(videoMetaActions.setMusicUrl, this.handleMusicUrl);

If at all.

Hey, lib author here.

Let me first explain Flux in five seconds.

Instead of mutating your models, any data mutation in your app is described as a plain object describing “what happened” (e.g. { type: LIKED_POST, postId: 42 }) and broadcasted globally. Models (called Stores in Flux) have no setters and change their internal state in response to specific mutation objects (called Actions).

The goal of Flux is to have single source of truth and make it easy to avoid race conditions and cascading updates. If some data is wrong, just repeat the same Actions in the same order, and you'll get the same data in Stores. Very easy to debug.

Now, for Redux.

It keeps the properties of Flux (mutations described as objects), but instead of Stores mutating internal state, it has Reducers—pure functions with (state, action) => state signature. While writing Flux apps, I noticed that the _essence_ of every Store I ever wrote was a reducer function.

It turns out that using pure functions instead of event emitters has many benefits: they are composable (https://gist.github.com/gaearon/d77ca812015c0356654f), it is possible to hot reload their logic (https://camo.githubusercontent.com/5688a6141e6a86baca5d25246...).

I wrote Redux for my React Europe talk about Hot Reloading and Time Travel (https://github.com/react-europe/cfp-2015/blob/master/live-re...). It got popular before I explained _why_ I made it. In my talk I show what kind of powerful devtools it is possible to build on top of Redux. The video of my talk will be up soon, you can check when it appears here: https://www.youtube.com/channel/UCorlLn2oZfgOJ-FUcF2eZ1A?app....

Also check out my article on the subject: https://medium.com/@dan_abramov/the-evolution-of-flux-framew...

EDIT: THE VIDEO IS UP! https://www.youtube.com/watch?v=xsSnOQynTHs

They're a bit more than just reducers. Given that you always package them with initial state they're a little more like "left folds" [0] or "Moore machines" [1] (they're isomorphic). What's neat about this is that noticing that structure describes a whole bunch of ways to compose machines and folds—in particular, there's parallel composition like Flux suggests ("all stores receive the same actions", your linked example, https://gist.github.com/gaearon/d77ca812015c0356654f) and sequential ("category-like") composition.

[0] https://hackage.haskell.org/package/foldl-1.1.0/docs/Control...

[1] https://hackage.haskell.org/package/machines-0.5.1/docs/Data...

Hi Dan,

Great job. Hot reloading is SO HOT .. in your hands!

Would you please share your plans for Redux, Redux DevTools and other tools you are working on?

What's your vision for React based tools in such quick changing environment?

I'm really scared to move all my projects to React base cause constant breaking changes. Coming packages splits in React 0.14, rush into ES6/7 rewrites, etc. is a huge hit for guys like me who can code only in free time outside of standard business hours.

I would rather follow someone with strong vision ;))) ... and it seems you got your own.

Please share what's on your mind.

P.s. And yee ... please do presentation at MoscowJS ;)) http://www.moscowjs.ru/ https://www.facebook.com/groups/moscowjs/ Ilya S

Hey Dan,

Redux looks awesome. I am using react-dnd and hot reloader on my current project and they are great. Thank you for all the great contributions you are making to the ecosystem.

The idea of modeling the store as a reducer is clever. Complication I see is that my action creators are often not pure functions (i.e. there is generally a side effect to update the database and persist the change). However, given the focus of redux on improving the dev workflow, I suppose database updates/side effects could be mocked out. How would you handle this scenario?

What would actually be awesome to have and go hand-in-hand with redux is an immutable write-only isomorphic database (for application state persistence), where you use the same initial state/reducer for redux and the database. Database stores initial state, logs actions and computes the current state using the reducer (and caches it) - much like redux on the client. Curious to hear what people think about this or if anyone has seen anything like it.

>Complication I see is that my action creators are often not pure functions (i.e. there is generally a side effect to update the database and persist the change).


Thank you! I've been reading about Flux for a while now but your simple explanation just made it click

People should really just use the actual name for it: CQRS There would be a lot less future confusion over what's flux or not. It's actually a really old design pattern called command query responsibility separation. http://www.codeproject.com/Articles/555855/Introduction-to-C...

Does it cope well with large amounts of data, and streaming of data? So far, all of the frameworks I have seen break down in such cases. And it is really a pain to pull a framework out of a project because it stopped meeting performance constraints.

Could you give an example of where a certain framework would break under large amounts of data?

There needs to be more web tools with hot reloading support

To begin, I'm not quite sure what flux is.

https://github.com/facebook/flux is this the flux it's for?

It seems opaque to me at this stage. It reminds me of when Google released Polymer. There was a lot of generic stuff - but no elevator pitch.

Explain to me in 30 seconds what's flux and where it sits?

Flux is two things: a library by facebook (which you linked to), and a set of vaguely specified ideas. It's the second definition this article (and most uses of the word "flux") refer to.

Flux is an architecture pattern for applications where a lot of logic can run on the client. Its goal is to disconnect changes to state (the "model" in MVC terms) from the effect that should have on the view. This assumes that the view is a layer that can cheaply update itself without knowing what part of the state changes - a full "re-render" should be cheap and effective. React is a library that allows this.

Once the view can update itself without knowing what state changed, one side of the disconnect between state and UI has been solved. The other side is how to manage state when user actions change it.

When the model is a big blob of mutable data, this is easy: just update whatever you want to update, trigger a full re-render of the view and be done with it. But this has two disadvantages: first, it's often difficult to serialize this model and send it over the wire, which means prerendering on the server for snappy startup times is difficult. Second, people often prefer the model layer to be built of immutable data, because that makes React re-rendering faster.

Flux tries to make working with serializable, immutable data easier by introducting what they call a "unidirectional data flow": user actions go into a "dispatcher", which in term knows which little sub-part of the model, called a Store, wants to turn that action into a data change. The stores, in turn, tell the view to re-render and that's it. The view can query the stores but not change the data in them: that's done only by sending actions through the dispatcher.

The core insight of Flux is that dealing with immutable data is pretty easy if you split the model up into a limited number of simple "Stores", the granularity of which determines much of how well Flux works for you. If you manage to get them not too big and not too small, dealing with immutable data is not difficult anymore and React gets snappy updates. And serializing immutable data to JSON is pretty easy, because it's guaranteed to be a tree, so prerendering both the HTML and the initial dataset on the server is a done deal.

Sorry, not 30 seconds. Does this help at all?

Personal commentary: I'm not convinced that Flux is the final solution. Before Flux was popular, I led a React team with a model layer that was plain old mutable JavaScript objects, and it worked remarkably well. It was a big cyclic graph of objects that all referred to one another. Typical oldschool OO data model design. The big disadvantage was that re-rendering was slower, but IMHO we need to find a better solution around that.

The guys who invented React said "what? all that spaghetti code just to keep model and HTML in sync? i just want to rerender every time just like we used to do with PHP on the server! i'm going to find a workaround" and invented the virtual DOM. In the same spirit, there has to be a way to make mutation of state simpler and still be fast and support universal ("isomorphic") apps. Mutable state is rather unpopular these days, but if there's one place where it shines, it's UI development.

Isn't the dislike of mutable state based on maintainability? i.e. more different things can poke at your state, the harder it is to reason about case and effect and the harder it is to prevent race conditions and a host of other problems.

I'm feeling this in a back-end app and I'm wondering whether I can make use of some of these concepts to make things more manageable.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact