A better Flux with DOM events

February 24, 2015 12:47 pm 7 comments

I have been discussing a lot lately with smart guys about what is the best way of organizing your application using React.js and I would like to share what I have learnt.

Facebook released react two years ago saying “Hey guys, here you have the V for your MVC web apps!” and it turned out to be a great V. But how should I organize the rest of the app? People tried to mix react views with backbone models then to try to fill the gap then, but those solutions were a bit overkilling.

Last year React guys appeared again to say “Hey guys, use Flux, your data should flow in just one direction”. The second commandament was really good too. Receiving the props from above and reducing component states reduce the complexity of developing web apps. But it made grow more questions in developers’ heads: where should I put the code to fetch data from the server? How can I handle async actions? How can a child component communicate with its parent?

The rise of Flux libraries

Whenever questions are made, people try to answer their own way, and a lot of custom flux implementations started to appear: Fluxxor, Reflux, Fluxible, Marty… Even I released my own implementation: Fluxify.

All of them do the same and all of them are incompatible with the others. Once you start using one implementation, your react components get highly coupled to that library, and it is not easy to switch from one to another.

But the way that React.js components are defined encourages to reuse and encapsulate them. Why can’t we use them like if they were web components?

Events to the rescue

Flux idea is great, flow like water my friend. But the way that Facebook propose to flow is pushing the water with the hand. Dispatching actions from the components is too imperative, our views need to say “Hey app, something happened” instead of “Hey app, do something”.

Events are the natural way of saying that something has happened in web pages. They have been used succesfully by HTML elements for years and it is the recommended way for the a web component to communicate with the world outside its shadow DOM. And the best part of events is that they are shipped by every browser, so why not to use them with react.js?

Flux with DOM events

It would be great to use React’s synthetic event system, but it has an event set defined and it is not possible to use it to emit custom events.

So let’s use DOM events. Some of you will think that DOM and React are not a good match, but this has nothing to do with fast rendering, it is about communicate user interaction to our app.

DOM events will replace Flux dispatcher and actions will react ( oops! I used the r word! ) to those events in order to update the stores. They should be rather called reactions.

So instead of having the traditional Flux diagram

traditionalFlux

Using events we have something simpler, aligned with some of the most popular flux implementations that don’t implement a dispatcher either.

eventFlux

Notice that the line that the line that binds the view with the reactions is dashed. The graph want to remark that Views are independent from the reactions, they will emit events but they don’t know anything about reactions.

We need also a hub where our reactions will be listening to the events. I think that the document object would be perfect. The events will be emitted by the DOM node of our components, so the reactions will wait for the events to bubble up through the DOM until they reach the document object, starting the reactions.

The reactions can be coordinated using events too. A reaction can emit new events on finishing, starting new reactions, so we don’t need the dispatcher’s waitFor method anymore. In this eventful system, async reactions can work the same way than sync ones, triggering events on finishing. At this point, if we have several reactions dependant from others you can use event stream libraries like RxJS or Bacon.js to make easier event handling if you want ( RxJS and React.js at the same time! ).

A simple example

Let’s make a simple counter with a button to increase.

You can see it working in this JSBin.

Communication children-parent

Using DOM events also make easier the communication between a parent its children components. Sometimes, it is handy that the parent manages the state of its children and, to do so, Facebook recommends to pass a callback to the child component. It is a messy solution, it generates some boilerplate code to store the callbacks and makes you develop your child components depending on functions that live outside them.

Since we have eventful components now, our parent component can now listen to children events to coordinate them, and the children will just execute its own code. Let’s create a selectable list:

This is the list working in a JSBin.

The selected item state is stored in the list instead of in the items, that way it is easy to have just one item selected at a time.

Conclusion

Using events for the communication of your components has benefits that can be spotted at the first use. It is not just making our components independent, moving the application logic to the reactions creates a clear C for the MVC pattern, taking it out from the Views and the Model, enforcing a clear separation of concerns.

If you liked the article, I have created a quick helper called flux-reactions to reduce boilerplate of using events on your components, every contribution is welcome!

If you are looking for a great Model to complete the MVC, I would recommend Freezer, because I am the author, but any other immutable store would make your development fly.

javi

Let’s push your website a bit further

My name is Javier Márquez and I have more than 10 years of web programming and web designing experience. If you have a difficult development to complete, maybe you can stop by and see what I can do for you. You can find me on and Twitter.

7 Comments - Leave yours

  • Berkeley Martinez

    Does this now make your component tied to the DOM? Since server-side rendering calls the render method of components, Item’s render function needs to define this.onSelect which will error out with document undefined.

    Although, I am of the opinion ditching the dispatcher in favor of event emitters or FRP using RxJS (Like Reflux or Rx-Flux), this implementation means no dependencies on other frameworks which I see now is the greater advantage.

    • Javi Marquez

      Yes your component is tied to the DOM. But since it is about user interaction and your user interacts with the DOM, your component is always tied to the DOM browser side, even if you are not using the DOM to trigger events in your component.

      In the server you hardly will find yourself with user interaction, and it is possible to ignore this DOM event behavior easily.

  • Guoliang Cao

    Great writeup! I like this idea and think React will be better and easier to use if this is built in.

  • Stardrive Engineering

    Like where this is going! Also just discovered the Rx.dom = {}; example on the RxJS site here:

    https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/events.md

    There is also more on RxJS and how it might be used as a loosely coupled event system for React here:

    https://github.com/fdecampredon/rx-flux/issues/10

    • Javi Marquez

      Thanks for your links. First one can be seen as the instructions to use flux with events and Rx, a must read if you like the events approach. I have already explained my point in the second link, it is a nice discussion :)

  • Stardrive Engineering

    Interesting how there are more of us starting to see through the Flux haze and using Rx instead: http://qiita.com/kimagure/items/22cf4bb2a967fcba376e

Leave a reply to Guoliang Cao


contact meAnything related to web development like javascript and CSS to create responsive designs, or PHP and node.js to make your website work properly, is my pleasure. If you have an interesting project in mind, I can help to make it real.