There are lots of flux or flux inspired libraries out there: they try to solve different kind of problems, but which one should you use? This article tries to give an overview on the different approaches.
What is Flux? (the original)
Ok, but why?
Flux tries to avoid the complex cross dependencies between your modules (MVC for example) and realize a simple one-way data flow. This helps you to write scalable applications and avoid side effects in your application.
Read more about this and about the key properties of Flux architecture at Fluxxor’s documentation.
Facebook’s original Flux has four main components:
singleton Dispatcher, Stores, Actions and Views (or controller-view)
From the Flux overview:
The dispatcher is the central hub that manages all data flow in a Flux application.
It is essentially a registry of callbacks into the stores.
Each store registers itself and provides a callback. When the dispatcher responds to an action, all stores in the application are sent the data payload provided by the action via the callbacks in the registry.
Actions can have a type and a payload. They can be triggered by the Views or by the Server (external source). Actions trigger Store updates.
Facts about Actions:
- Actions should be descriptive:
The action (and the component generating the action) doesn’t know how to perform the update, but describes what it wants to happen. – Semantic Actions
- But shouldn’t perform an other Action: No Cascading Actions
- About Actions dispatches
Action dispatches and their handlers inside the stores are synchronous. All asynchronous operations should trigger an action dispatch that tells the system about the result of the operation – Enforced Synchrony
Later you will see that Actions can be implemented and used in different ways.
Stores contain the application state and logic.
Every Store receives every action from the Dispatcher but a single store handles only the specified events. For example, the User store handles only user specific actions like
createUser and avoid the other actions.
After the store handled the Action and it’s updated, the Store broadcasts a change event. This event will be received by the Views.
Store shouldn’t be updated externally, the update of the Store should be triggered internally as a response to an Action: Inversion of Control.
Views are subscribed for one or multiple Stores and handle the store
When a store
change event is received, the view will get the data from the Store via the Store’s getter functions. Then the View will render with the new data.
- Store change event received
- Get data from the Store via getters
- Render view
You can find several Flux implementations on GitHub, the most popular libraries are the followings:
Lots of people think that Flux could be more reactive and I can just agree with them.
Flux is a unidirectional data flow which is very similar to the event streams.
Now let’s see some other ways to have something Flux-like but being functional reactive at the same time.
Reflux has refactored Flux to be a bit more dynamic and be more Functional Reactive Programming (FRP) friendly – refluxjs
Reflux is a more reactive Flux implementation by @spoike because he found the original one confusing and broken at some points: Deconstructing ReactJS’s Flux
The biggest difference between Flux and Reflux is that there is no centralized dispatcher.
Actions are functions which can pass payload at call. Actions are listenable and Stores can subscribe for them. In Reflux every action act as dispatcher.
Reflux provides mixins for React to listen on stores changes easily.
It provides support for
sync actions as well. It’s also easy to handle async errors with Reflux.
In Reflux, stores can listen to other stores in serial and parallel way which sounds useful but it increases the cross dependencies between your stores. I’m afraid you can easily find yourself in a middle of circular dependency.
A problem arises if we create circular dependencies. If Store A waits for Store B, and B waits for A, then we’ll have a very bad situation on our hands. – flux
There is a circular dependency check for some cases in reflux implemented and is usually not an issue as long as you think of data flows with actions as initiators of data flows and stores as transformations. – @spoike
The Flux architecture allows you to think your application as an unidirectional flow of data, this module aims to facilitate the use of RxJS Observable as basis for defining the relations between the different entities composing your application. – rx-flux
- A store is an RxJS Observable that holds a value
- An action is a function and an RxJS Observable
- A store subscribes to an action and updates accordingly its value.
- There is no central dispatcher.
When the Stores and Actions are RxJS Observables you can use the power of Rx to handle your application business logic in a Functional Reactive way which can be extremely useful in asynchronous situations.
If you don’t like Rx, there are similar projects with Bacon.js like fluxstream or react-bacon-flux-poc.
If you like the concept of FRP, I recommend you to read @niklasvh‘s article about how he combined Immutable.js and Bacon.js to have a more reactive Flux implementation: Flux inspired reactive data flow using React and Bacon.js
niklasvh’s example code for lazy people: flux-todomvc
Omniscient is a really different approach compared to Flux. It uses the power of the Facebook’s Immutable.js to speed up the rendering. It renders only when the data is really changed. This kind of optimized call of the render function (React) can help us to build performant web applications.
Rendering is already optimized in React with the concept of Virtual DOM, but it checks the DOM diffs what is also computation heavy. With Omniscient you can reduce the React calls and avoid the diff calculations.
What? / Example:
Imagine the following scenario: the user’s name is changed, what will happen in
Flux and what in Omniscient?
Flux every user related view component will be re-rendered because they are subscribed to the user Store which one broadcasts a change event.
Omniscient, only components will be re-rendered which are using the user’s name cursor.
Of course it’s possible to diverse Flux with multiple Stores, but most of the cases it doesn’t make any sense to store the name in a different store.
Omniscient is for React, but actually it’s just a helper for React and the real power comes from Immstruct what can be used without Omniscient with other libraries like virtual-dom.
It may not be trivial what Omniscient does. I think this todo example can help the most.
You can find a more complex demo here: demo-reactions
It would be interesting to hear what companies are using Omniscient in production.
If you do so, I would love to hear from you!