React killed the MV star

Tal Weinfeld
4 min readOct 3, 2015

--

React has been drawing a lot of attention in the last couple of years, and for a very good reason — it’s groundbreaking approach has moved web-developers one huge step away from the DOM, liberating us from the meticulous responsibility of keeping it up to date with our business data, while doing our best to successfully “bail out” of the DOM’s endless permutations. One thing React wasn’t designed to do though, is to provide a clear architectural path for developers to follow when designing their app.

In this post I’ll survey Flux and demonstrate how it could be interpreted according to the principles of the good old Model-View-Controller pattern.

Before diving into Flux, let’s try to define React’s location in the MVC triangle. Right now you’re probably saying to yourself “View… duh?” — and that’s undoubtedly the correct answer! There is no other, more suitable place to position React than in the “View” slot, but does it fully cover all its responsibilities?

A typical front-end application View is responsible of everything that “comes into contact” with the “flesh and blood” end-user. This very often means DOM manipulations, but it can also include stuff like canvas/WebGL draws, audio/video playback control, browser title changes and more. Taking it into consideration means that React is ill equipped to support the complete gamut of View concerns!
This part is often overlooked by MVC designers — and in an effort to make this square peg fit into a round hole, “duct-tape” solutions sometimes pop up.

Ok, now that we have our partial “View”, let’s take a look at Flux.

Flux is Facebook’s “a la carte” answer to React’s “missing link”. It paves an architectural path for developers, and provides some useful implementations as well as interface documentation for some of its components.

Flux’s foundations are:

  • Dispatcher: An “Event Bus” of sorts, similar to a “Fan-Out” bus where messages pushed are distributed to all consumers, regardless of their content. An application should contain a single dispatcher to handle all messages (called “Actions”) in it.
  • Store: A data storage unit. Stores subscribe to the dispatcher, and when an Action is received, they process it by updating their own data, then they can send out events to indicate that they’re done.
  • View: A React component, or tree of components. It subscribes to stores’ events at it’s “root” (top component). When an event is triggered, it pulls out the relevant pieces of data out of all respective stores, then updates its “state”, which triggers a “render”.
    If UI events are triggered, the View responds by creating the required Action messages, and pushes them into the Dispatcher.

Now let’s try to translate these to “MVC lingo”:

  • Dispatcher: The Dispatcher logic is pretty basic — it relays Actions. Actions could generally be regarded as “Controller”, since they do not make operational decisions regarded as either View nor Model.
  • Store: The Store’s name may suggest that it’s a Model, but this is actually not entirely true here. In fact, Flux Stores may contain substantial portions of Controller logic.
    Models in MVC are usually designed to store state. Any logic they contain strictly serves that goal. This means Models are “oblivious” to the world around them. So, for instance, while we can ask a Model to “store new user X”, we cannot request it to “process a new user’s registration”.
    Flux’s Stores, on the other hand, are OK with following instructions originated at the application domain. An Action like “process a new user’s registration” is totally acceptable. Such action may trigger an elaborate logic, affecting many different areas of the Store’s retained state (for instance it may add a log line to audit the action). Stores may even rely on other stores to accomplish their Action’s logic.
  • React Component: As mentioned earlier, React’s component is serving as a partial View, but there are two additional important roles it serves in Flux:
  1. Components listen for changes in Stores relevant to them. When a change is detected, a Component pulls any data it needs from Stores it watches, processes it, then sets its own state accordingly. The new state then triggers a render.
  2. When the Component receives interactions from the user, it creates actions to address them, and delivers them to the Dispatcher.

Notice that these “extra” two roles are usually implemented only in the top-most Component on a Component tree, other components do not usually interact with Stores or the Dispatcher directly. But since we are set out to classify the Component’s location as a whole, it would fit best under both “View” and “Controller”.

To sum everything up:

Flux through the prism of MVC

Every component in Flux contains some portion of Controller logic. The largest parts of it will most probably be found within the application’s root Component (where UI-related Actions are created), but substantial volumes of it would be sprinkled all across the application’s Stores. This is the reason why, while Flux allows you to easily refactor and reuse most of your React-Components, doing the same for any other of its ingredients (Stores/Components) could prove a bit more tricky.

To help mitigate this situation, keep as much of your application’s Controller logic tucked away inside individual modules, and contain as little of it as possible directly in Store/Component modules. Removing cross-store dependencies could also improve reusability.

--

--