Here it goes; The main thing about flux, in my opinion is this:

We can label any piece of code in a flux based front-end application with one of the following 3 labels:

Data (stores, actions, action creators, reducers etc)

Event Handlers (created either by the user or by other agents)

Data Consumers (views, sagas and other agents)

The Flux Triangle

From event handlers to the store(s)

External agents trigger event handlers in our applications. We run business logic in those handlers (either completely in our application, or by delegating to other external agents) and display some sort of result on the screen. The process is repeated over and over. The main external agent is the User.

I’m calling the user and external agent because it’s behaviour is black-boxed. We don’t know when a new click even will happen. We just know AFTER it happens via event handlers. We can replace “click” with pretty much any user action. The flow of the application will be the same each time.

In a similar way we can examine a fetch request done by the browser. The api server that handles the request is also a black-boxed entity, an external agent which will do something on it’s own, without us know how it did it. We get a response back the same way as we did from the User, thru an event handler.

From External Agents to the Data Layer

A couple of examples of events that are generated by external agents are:

User mouse and keyboard events, browser resizes and orientation changes

Ajax status events and receiving socket messages

Anything that goes outside our application code in any way can be considered the work of an external agent which will communicate with the application thru event handlers.

Yes, the browser is the actual gatekeeper that does all the work in between the application code and the other applications/entities, but since it’s behaviour is always the same, we can consider it the execution environment, not the one and only external agent.

From store(s) to data consumers

Right after the data has been changed, any entity that needs the new data will be ‘triggered’ by a mechanism similar to event handlers only this time we are listening to the data changes of our application. This time, we consume the data of our own application, not the data of some external entity that made some message or content available to us.

The main consumer of the data is usually the View Layer (or React components most of the time these days). But the view layer is not the only consumer of data that can exist in an application. For example, a saga can be another type of consumer which could run a fetch request, or post something to the server for us.

I think that the common ground between the view layer and a entity that works with an external agent is the following:

Both the view layer and a entity responsible for asynchronous operations consumes data and then reacts thru event handlers to external interaction.

In the case of the view layer, we consume the data in order to display the UI, and the user, asynchronously triggers event handlers.

The view layer seen as a data consumer

In the case of a saga responsible for fetching a list of users, we consume a message that request the start of the fetch operation, and then the http response coming from the API server asynchronously triggers event handlers.

The view layer and any other data consumer, from the point of view of the data, are the same thing. Entities getting fed by the data, and asynchronously triggering event handlers which in the end create actions to be dispatched in the data layer.

Generalisation of a Data Consumer

Stores are breakpoints in the flow

The beauty of separating concerns this way is that we can split technical functionalities from business logic easily.

Each main application flow can be broken down in small, testable steps. Instead of having to mock complicated flows that follow lots of steps in order to reach a certain application state, we can simple feed the right data into data consumers and assert that they behaved accordingly.

In a similar way, we can test technical entities and make sure they dispatch the right type of actions based on whatever it is they are doing — like resizing the window, changing orientation, focusing a input field, failing an ajax request — .

Conclusion

Thinking in Flux simplified the way I think about complex applications. It made everything fit into these 3 categories (data, things that change the data, things that use the data) and it made unit testing significantly easier.

Did I miss something? Do you agree or disagree with my perspective? Feel free to let everyone know our opinion.