An application architecture based on a unidirectional data flow
An application architecture for React utilizing a unidirectional data flow.
Please read the blog post announcing Flux: "An Application Architecture for React".
Going further, please take a look at our in-depth examination of action creators and the dispatcher.
Basic example: TodoMVC
Slightly more complex example: Chat Client
Flux is more of a pattern than a framework, and does not have any hard dependencies. However, we often use EventEmitter as a basis for
Stores and React for our
Views. The one piece of Flux not readily available elsewhere is the
Dispatcher. This module is available here to complete your Flux toolbox. The Dispatcher's one dependency is the
invariant module, also included here.
Flux is available as a npm module, so you can add it to your package.json file or run
npm install flux. The dispatcher will be available as
Flux.Dispatcher and can be required like this:
var Dispatcher = require'flux'Dispatcher;
Clone the repo and navigate into the resulting
flux directory. Then run
This will run Gulp-based build tasks automatically and produce the file Flux.js, which you can then require as a module.
You could then require the Dispatcher like so:
var Dispatcher = require'path/to/this/directory/Flux'Dispatcher;
The build process also produces de-sugared versions of the
invariant modules in a
lib directory, and you can require those modules directly, copying them into whatever directory is most convenient for you. The flux-todomvc and flux-chat example applications both do this.
Flux applications have three major parts: the dispatcher, the stores, and the views (React components). These should not be confused with Model-View-Controller. Controllers do exist in a Flux application, but they are controller-views -- views often found at the top of the hierarchy that retrieve data from the stores and pass this data down to their children. Additionally, action creators — dispatcher helper methods — are often used to support a semantic dispatcher API. It can be useful to think of them as a fourth part of the Flux update cycle.
Flux eschews MVC in favor of a unidirectional data flow. When a user interacts with a React view, the view propagates an action through a central dispatcher, to the various stores that hold the application's data and business logic, which updates all of the views that are affected. This works especially well with React's declarative programming style, which allows the store to send updates without specifying how to transition views between states.
We originally set out to deal correctly with derived data: for example, we wanted to show an unread count for message threads while another view showed a list of threads, with the unread ones highlighted. This was difficult to handle with MVC — marking a single thread as read would update the thread model, and then also need to update the unread count model. These dependencies and cascading updates often occur in a large MVC application, leading to a tangled weave of data flow and unpredictable results.
Control is inverted with stores: the stores accept updates and reconcile them as appropriate, rather than depending on something external to update its data in a consistent way. Nothing outside the store has any insight into how it manages the data for its domain, helping to keep a clear separation of concerns. This also makes stores more testable than models, especially since stores have no direct setter methods like
setAsRead(), but instead have only an input point for a data payload, which is delivered through the dispatcher and originates with action creators.
A unidirectional data flow is central to the Flux pattern, and in fact Flux takes its name from the Latin word for flow. In the above diagram, the dispatcher, stores and views are independent nodes with distinct inputs and outputs. The action creators are simply discrete, semantic helper functions that facilitate passing data to the dispatcher in the form of an action.
All data flows through the dispatcher as a central hub. Actions most often originate from user interactions with the views, and action creators are nothing more than a call into the dispatcher. The dispatcher then invokes the callbacks that the stores have registered with it, effectively dispatching the data payload contained in the actions to all stores. Within their registered callbacks, stores determine which actions they are interested in, and respond accordingly. The stores then emit a "change" event to alert the controller-views that a change to the data layer has occurred. Controller-views listen for these events and retrieve data from the stores in an event handler. The controller-views call their own
render() method via
forceUpdate(), updating themselves and all of their children.
This structure allows us to reason easily about our application in a way that is reminiscent of functional reactive programming, or more specifically data-flow programming or flow-based programming, where data flows through the application in a single direction — there are no two-way bindings. Application state is maintained only in the stores, allowing the different parts of the application to remain highly decoupled. Where dependencies do occur between stores, they are kept in a strict hierarchy, with synchronous updates managed by the dispatcher.
We found that two-way data bindings led to cascading updates, where changing one object led to another object changing, which could also trigger more updates. As applications grew, these cascading updates made it very difficult to predict what would change as the result of one user interaction. When updates can only change data within a single round, the system as a whole becomes more predictable.
See the CONTRIBUTING file for how to help out.
Flux is BSD-licensed. We also provide an additional patent grant.