When I started a new project few months ago I opted for ReactJS. As I was new to the concepts behind React I decided not to choose the Flux architecture pattern, which is often mentioned together with ReactJS. Of course, I started to cross-read articles about Flux, but honestly I had difficulties to understand the great "WHY?".
I thought that the data-binding I am used to since AngularJS would be sufficient for my purposes. The project evolved to something larger than we all imagined initially (while it is still a relative small application). Nowadays, the project consists of more than hundred components, some of them with composition hierarchies of four or five levels. Keep the latter detail in mind, as it becomes important a little bit later. So, I started the project without Flux and today I regret it, because a) Flux is simple and b) refactoring the current project to Flux needs some cumbersome work and - more important - time. In this article I try to explain, why Flux is better than a traditional data-binding for component oriented applications.
Components - an old concept
Before I start to explain what Flux is, I will emphasize an important characteristic which is inherent for an application based on components. To remember, ReactJS (and also others like Polymer/WebComponents, FlightJS, RiotJS, etc.) favors an apparently emerging paradigm for front-end: Component Based Development (CBD)
In CBD certain parts of the software are encapsuled, reusable, and composable modules usually called components. The real big thing is the composability of components. About eight to ten years ago there were the great hype of Service Oriented Architecture (SOA). The fundamental idea behind SOA is the ability to compose different functionalities encapsuled as services. You can build a larger (more complex) service based on several smaller services - let's call them micro-services. Huh? Isn't it a familiar buzz-word? It is exactly what CBD does on a 'intra-application' level and usually, but not explicitly, applied for visual aspects. On server-side this has been done for years already with for example JSF and ASP.NET Web Forms. Desktop applications developed with common UI frameworks like Qt, or WinForms also rely on a component-based concept. As you see the idea of componentization is nothing new.
Finally, the component approach has arrived at the web front end - and the community is accepting it. ReactJS is currently the most popular candidate, but soon more libraries and frameworks will surge (Angular 2.0?). So far, so good.
Imagine an web application, which is scattered in several small
modules components. But wait! Imagine that a component is composed of other components ("micro-components"). This may look like this:
We have a component called editor-frame and the two components editor-content-person, and editor-content-product embedded into instances of editor-frame. The content components provide the individual data for person and product respectively, while the frame component is provides the save button. That means, that we need to define our data flow, and we have two options:
- We pass the contents data to the host component (editor-frame), which may happen while typing, or on button click.
- We let the data inside the child component (editor-content), and inform it when save button was clicked.
Our decision affects where we implement the persistence logic, and also maintaining the state - maybe we want to clear the fields after successful saving. Ideally, we follow the "Don't repeat yourself"-principle (DRY), e.g. the persistence is done in the host component. So, we would decide for the first option: passing data to host. This way we also follow the ReactJS documentation, which recommends to keep states in most outer host components:
A common pattern is to create several stateless components that just render data, and have a stateful component above them in the hierarchy that passes its state to its children via
props. The stateful component encapsulates all of the interaction logic, while the stateless components take care of rendering data in a declarative way.
Although, it is taken from the ReactJS documentation, this pattern is applicable for every component-based approach. The way how the data is passed to hosts is just an implementation detail. But what happens if our person data changes outside of the content component and we want to update the form? We pass the new data down to the content (in case of ReactJS using props), exactly as described in the cited text above. Therefore, we need some mechanism which knows when data has changed, so that we can pass it downwards to the child.
This is already a quite complex scenario, but it gets more complex if you have a deeper hierarchy, which is common in a component based world. Then you need to keep up the data flow for all levels, which can result in a lot of messy and redundant code. I know it, because I passed through it, and obviously the guys at Facebook, too. This is when Flux comes into the game.