top | item 8097776

Facebook Flux – Application Architecture for Building User Interfaces

255 points| diggan | 11 years ago |github.com | reply

57 comments

order
[+] jefftchan|11 years ago|reply
It's great to see Facebook releasing code for Flux. Hope to see more in the future. Here are some other implementations of Flux for anyone who's interested: https://github.com/BinaryMuse/fluxxor https://github.com/jmreidy/fluxy https://github.com/yahoo/flux-example

We recently adopted this architecture for a medium-scale project. The unidirectional data flow has greatly reduced code complexity for us. We're still not satisfied with our server syncing strategy. Seems like actions are the best place to sync data, but how do you deal with interdependent actions?

[+] jmreidy|11 years ago|reply
I'm the author of Fluxy and would be happy to answer any questions here. The big benefits of Fluxy vs other Flux approaches is that 1) Stores are built on top of immutable data structures (via ClojureScript / mori) 2) Server side rendering is baked in (or will be as of 0.4)

I'd also mention https://github.com/spoike/reflux as an implementation.

[+] mridgway|11 years ago|reply
We've been exploring Flux pretty heavily here at Yahoo and the idea of utilizing React + Flux stores on the server-side as well. The Yahoo flux-example you linked to is using our own dispatcher (https://github.com/yahoo/dispatchr) that does away with the singleton pattern all of the other Flux documentation and examples have used, making it safe to use on the server.
[+] kaonashi|11 years ago|reply
Usually I have an action call out to some DAO class which encapsulates an HTTP request and returns a promise, then just firing off a different action in the done and fail callbacks.
[+] forwardslash|11 years ago|reply
Could you describe what you mean by interdependent actions? As in, chains of actions?
[+] xtrumanx|11 years ago|reply
I'm still somewhat unclear on the point of the Dispatcher and Actions and they simply feel like needless indirection to me.

For instance, in the flux-chat app within the linked repo, the MessageComposer component calls `ChatMessageActionCreators.createMessage(text);` when the user press the enter key to submit a message.

To find out how that ends up affecting the application, you need to jump around more than a couple of directories to find out how it's all wired up.

I just cut out the middlemen and directly interfaced my Stores from my components. My Store then emits a change event as usual and other components that are subscribed to the change event than refetch their state. That part of Flux makes perfect sense to me. The need for Dispatchers and Actions don't.

To be fair, I didn't start looking into Flux until my app starting growing large enough that I started feeling the pain of my lack of architecture. The Stores and the event emitter solved my immediate problems. Perhaps if my app grows even larger, the Dispatcher may come in handy.

[+] e1g|11 years ago|reply
You are absolutely right that actions are just another level of abstraction that come with their own pain, and if the pain they bring does not relieve an even greater pain of not having them then there is no reason to introduce them yet.

In our app, we started feeling the growing pain of a laissez faire approach to internal comms. For us, a user interaction can generate multiple logical state changes in the app, and several related interactions can cause similar/identical changes to take place. So for us, "User Interaction->App Change" is a many-to-many relationship, and Actions help us to wire them together really well. Couple examples -

1. Opening a modal with the detail view of the item. This can happen in several ways (a user click, onload, keyboard shortcut, app event), and it involves multiple steps (ui cleanup, fetching of more info, etc). Having an actions allow us to guarantee that when we want X to happen in the app, all necessary steps will be taken regardless of what causes X or in how many places.

2. Capturing analytics. We log all key interactions for internal analysis, and some events simply do not belong in the store/ViewController/component, so we capture in within the relevant Action. Low-level events are captured within components (e.g. did they press the 'save' button or hit enter), while others are app-level actions (e.g. 'view details') and are captured within Actions. Bonus - as per the point #1 for us multiple user interactions can cause similar app changes, but by also capturing the event within Actions we can easily track all triggers - e.g. was the 'view details' caused by a clicking on a link, using a shortcut, or another app-level change.

3. Refactoring. Most of the app UI is aware of only two things - Actions and (to a lesser extent) getState() of relevant stores. This means that as long as we keep the public interfaces of those two unchanged, we can refactor or even change the implementation as much as we need. Just last week we swapped the inhouse filtering/sorting implementation a for new one based on Crossfilter which caused a comprehensive rejigging of the stores' behaviours and methods, and because we kept the same public contract it had zero impact on the UI (besides a noticeable speed improvement).

Pardon the flawed comparison, but for us actions are useful in a similar way that interfaces or MVC controllers are useful - as long as you keep them lightweight and semantic, they provide predictable and reliable endpoints for the app regardless of what turmoil happens behind the scenes.

[+] HeyImAlex|11 years ago|reply
Came to write the exact same thing. I chatted with some other people on the react irc channel about it and interfacing with stores directly seems to be pretty common. It's been working well for me so far in the smallish app I'm writing now.

To expand a little, I have trouble identifying what the difference between these two flows are;

    (something) -> store method -> change event
    (something) -> "action" -> store method -> change event
Feels like actions on the dispatcher are an unnecessary level of indirection when I have to know that I'm calling a store method under the hood just by virtue of knowing the action to call. I understand batching events and things like that, but manually wiring seems like a really boilerplate heavy solution to the problem.

Now that I'm writing this, I can kind of see the usefulness in making reusable components that can interact with stores. I guess I just felt like reusable components would never interacted with stores (as that's handled by controller-views which are pretty much application specific). But even then they need access to the dispatcher, and if you can inject that dependency then you can inject the store itself...

Sorry for the stream of consciousness, it's my lunch break...

[+] alec_heif|11 years ago|reply
Another benefit is that the Dispatcher handles all the ordering of updates for you. If you have complex relationships between your stores or even if they just must handle updates in a certain order, by sending all updates through the dispatcher you can also force a partial ordering of store updates through dispatcher.waitFor(<other store>)
[+] btown|11 years ago|reply
You can imagine that a key command, a click on a button, or even a command originated from a remote control that arrives proxied over a WebSocket - all of these could create the same Action. Each Store shouldn't care, or have any interest in, what component created that Action. And you should be able to add new Stores and new interaction types at runtime, as if (in music production) you were plugging in a plug-and-play MIDI keyboard and simultaneously adding a new audio plugin that reacts to any MIDI input. The Dispatcher removes any dependencies between these components; everything just needs to know about the Dispatcher.
[+] ComNik|11 years ago|reply
Because I didn't want to add so many layers at once, I just implemented Stores -> ControllerView -> View -> direct Store call.

As far as my understanding goes that should be fine for most use-cases. The only reason that really requires a Dispatcher would be synchronization of the incoming Store mutations.

[+] driverdan|11 years ago|reply
I previously spent time reading about Flux, watching the videos, looking at Flux libs like Fluxxor and it seems overly and unnecessarily complicated to me. The actions layer specifically seems unnecessary as it could be implemented at the Store / model layer. The dispatcher is an event queue system with support for dependencies.

To me it makes a lot more sense for React components to push an event directly onto a pubsub event queue which then dispatches accordingly. When data changes anywhere it fires an event that then passes new state to the top level React component. Most of the actions you do to data are boilerplate and can be greatly simplified from Flux.

What am I missing? Why is it so complex?

[+] lebek|11 years ago|reply
Seems like actions were designed to encapsulate update logic that doesn't belong in the store (e.g. update ordering when multiple stores are involved). A pubsub event queue wouldn't make this very easy.
[+] fisherwebdev|11 years ago|reply
The Dispatcher is not an event queue system, but rather a registry of callbacks. This is a significant difference. The callbacks may be invoked in a specific order, synchronously, so that dependencies between Stores are managed effectively. Stores declare their own dependencies -- the Dispatcher knows nothing of the internals of Stores -- through the use of the dispatcher's waitFor() method.

Yes, you don't absolutely need the ActionCreator helper methods. You could call AppDispatcher.handleViewAction() or even AppDispatcher.dispatch() directly in the View. But keeping these things separated out keeps the code nicely organized and keeps application logic out of the View. Additionally, I find it helps to maintain a mental model where the only way into the data flow is through the creation of an action, codified in the library of ActionCreators.

[+] neves|11 years ago|reply
It has a fine explanation of the pattern: http://facebook.github.io/react/docs/flux-overview.html but what isthe reasoning in using this architecture? Or in pattern speak, what are the forces that this pattern is considering? I can't find a clear explanation about which problems is it trying to solve.
[+] tracker1|11 years ago|reply
In larger web based applications, tracking down side effects becomes increasingly difficult with patterns that implement two-way data binding (observables) or ad-hoc injection. This also in part takes into account part of why React renders the way it does. With the flux pattern(s) along with React's rendering pipelines, you can have heavy data flows, with minimal side effects and a slightly easier time in terms of tracing the flow of data.
[+] kaonashi|11 years ago|reply
Encouraging composition and simplifying event flow.
[+] rubiquity|11 years ago|reply
I've been using React quite a bit but haven't had a need for Flux. Using React to implement all of my UI concerns, combined with Backbone for easy to use persistence and modeling, has worked wonderfully for me. YMMV :)
[+] rjn945|11 years ago|reply
I agree. The combination of Backbone models/collections and React views bound together by React.Backbone[1] so that the views automatically re-render after any changes to the models/collections has made the data-heavy application I'm working on surprisingly easy to develop.

The real issue I've been having React -- that I'd I like to see dealt with by a library/design pattern -- is dealing with transitions between view states. Re-rendering the view on any data change can result in very abrupt changes. For instance, my app displays multiple lists of items. When the user edits an item, that can result in the item suddenly disappearing from underneath their cursor to reappear somewhere else in that list, in a different list, or nowhere within view.

I've been able to handle each issue of this nature as it arises in an ad-hoc fashion, but I'd really like a more formalized way in React to say, "when attribute X changes, use transition Y to change from the old view state to the new one".

Does anyone know of an existing solution to this problem?

[1] https://github.com/usepropeller/react.backbone

[+] clivestaples|11 years ago|reply
I think this is the best combination of libraries I've ever used, but given how impressive React truly is, I'm sure I'll see the Flux light soon enough too.
[+] voyou|11 years ago|reply
A lot of this seems like it's just MVC, except what they call the "View" is a traditional MVC Controller (the UI element that handles user interactions and sends these to the Model), what they call the "Controller-View" is a traditional MVC View (something that gets notified when the Model changes and displays that change to the user), and what they call the Dispatcher is what traditional MVC calls the Model.

They write "Flux eschews MVC in favor of a unidirectional data flow", but MVC already has a unidirectional data flow (Controller -> Model -> View). Is this just a case of those who don't understand MVC are compelled to reinvent it?

EDIT: Actually, the main addition over MVC seems to be that the Stores declaratively specify their relationships between one another (which are then resolved by the dispatcher), rather than the developer writing a specific Model implementation that explicitly orders the changes to related elements of the model. I'm a bit suspicious that this would be less explicit, and so harder to maintain, but maybe I'm wrong.

[+] augustl|11 years ago|reply
The main difference between Flux and MVC is the unidirectional data flow. In MVC, a controller updates a model which updates a view which again talks directly to a model that might invoke another view which again might cause a model update, and so on. In Flux, the only thing a view can do is to invoke actions on the top-level dispatcher. Furthermore, views are never partially updated, they are always re-rendered from scratch every time (like you typically do in the back-end).
[+] hcarvalhoalves|11 years ago|reply
It's easy to integrate with Backbone if you want for this kind of architecture, as it already implements events and stores. I've found it requires less boilerplate than the example in the repo.
[+] markplindsay|11 years ago|reply
I just wrapped up the initial version of a medium-size app using React. It was my first use of the library in production.

I had originally used Backbone.Model and Backbone.Collection in conjunction with React. But after reading about Flux on the React blog and watching the video explanation back in May, it only took me a week to replace all of my Backbone models and collections with Flux singleton-stores. Coupled with Andrey Popp's react-router-component[0] (now replaced by rrouter[1], I think?), I was able to remove Backbone from the project entirely.

I think that Flux is more flexible than Backbone. I really like the ability for a store to take on characteristics of both models and collections. It is also easy to combine many different external resources to compose the "one true source" of a particular type of data for many different components. I don't feel any particular need to bring back a Backbone dependency in future React projects.

[0] https://github.com/andreypopp/react-router-component

[1] https://github.com/andreypopp/rrouter

[+] colinhowe|11 years ago|reply
We've been playing with this architecture. It makes testing a lot easier - you just shove data in where needed and things pop out the other end. It also forces us into splitting things up in a more sensible manner. Along with easier testing is easier reasoning.

That said, like most new architectures/frameworks finding a big example (not just a TODO app) is really hard. We are currently prototyping a big app using React/Flux and we find ourselves having to question ourselves a lot more than we'd like.

[+] state|11 years ago|reply
Is there any chance your code is public?
[+] api|11 years ago|reply
FB seems to be doing some amazing work trying to make the web a more tolerable UI platform.

Once we finally have a good, solid, stable UI building consensus in HTML5/JS, it'll not only be possible to use it for the web but for the desktop too via node-webkit / atom-core.

[+] fiatjaf|11 years ago|reply
How does this compare with FRP?

I've been thinking about this and concluding that React wouldn't benefit even a little from those FRP libraries and architecture, it is already quite functional reactive. Am I wrong?

[+] lightblade|11 years ago|reply
React is not functional reactive by itself. Although there's no stopping people from integrating it with other FRP libraries.
[+] fnordsensei|11 years ago|reply
This looks very interesting, and if I'm not mistaken, slightly reminiscent of how apps are built with Om (using core.async for dispatch and atoms for storage).
[+] joekrill|11 years ago|reply
Excellent! Been waiting to see an "official" implementation of this. There's a lot of different information floating around about how Flux architecture "should be done", but I've been waiting anxiously to see how Facebook actually implements it/suggests it be implemented.
[+] igorgue|11 years ago|reply
I know is stylized as "f.lux" but fuck man...

Why does big companies do that? Just recently Apple's Swift and now Facebook's Flux.

[+] notduncansmith|11 years ago|reply
Flux (stylized "f.lux") refers to the awesome screen dimming/coloring software: https://justgetflux.com/ Completely unrelated, but I highly recommend it for anyone who stares at a screen for a living.
[+] driverdan|11 years ago|reply
What are you talking about? Facebook is calling it "Flux" not "f.lux".