We use cookies on our website, hope you don’t mind. Just imagine a plate of delicious meringues, they look like clouds. Read more

Development

React.js – You Might Not Need Flux

Share this Article on:

Stay in touch. Subscribe to our Newsletter

React gains the hearts of many javascript developers since its release in 2013. Because of an unconventional JavaScript extension (JSX), world wide known conferences, custom dev tools and proper documentation many eyes turned to Facebook’s tools. Big players such as Uber, Netflix, Slack, Yahoo talk about rewriting code with React.

Its community is also very active, enthusiastically willing to create new open source components (In fact lots of them). The idea of building apps with components already caught on in the way web-apps are developed. Surprisingly, WebComponents did not take part in this success. There is another big figure next to React – Flux.

What is Flux?

Flux is unidirectional data flow architecture. We should think about it as a pattern, not as a framework although Flux is also the name of a framework using flux architecture (your confusion is justified). Data in a Flux application flows in a single direction. It should make a programmer’s work more pleasant because it is easy to build and debug a data flow step-by-step.

The grounds of Flux are:

  • Data in a Flux application flows in a single direction (a new action can be triggered from View, see below)
  • The system should know as little as possible about the other objects in it
  • Flux is framework-agnostic and could be used standalone or with any javascript framework.

React.js - You Might Not Need Flux
There are lots of Flux implementations: Flux comparison by example

Let’s begin with describing the problem that Flux is trying to solve. React deals only with the View application layer. It did not provide any satisfactory data flow guidelines for building apps. The only react-way to handle data is passing it down in the component tree. Passing callback 4 levels down is not the right way to go. So we started to look for alternatives to avoid tedious work.

Why Flux is so good

Flux makes the data flow easy to track and manage. It standardizes synchronisation between different components as React does not provide any data bus itself. It should limit situations like “There is one guywho knows how this piece of code works, but he’s on a trip around the World”. You should just know, where data comes from, and where it goes next. The fact that it’s easy to follow what’s going on is the key benefit over two-way binding based systems.

Both Flux and React takes lots of good stuff from functional programming. Actions passed to Dispatcher are immutable. The same with components’ `state` and `props`. A programmer is also encouraged to write stores and action creators as pure functions.

It has a huge community, so you’ll always find an answer or applications using it.

Why Flux is so bad

Flux suffers from many reasons

  • The learning curve is pretty high in comparison to solutions, we just to.
  • There are more than a dozen of flux implementations. Some of them fix one problem to bring another.
  • Most of Flux implementations rely on singletons making it very hard to encapsulate components instances between each other.
  • Using Flux is laborious because of the oversized boilerplate. Even the example from Facebook’s sample Flux implementation brings lots of redundant code:

constants/ChatConstants.js

module.exports = {
  ActionTypes: keyMirror({
    CLICK_THREAD: ‘CLICK_THREAD’,
    CREATE_MESSAGE: ‘CREATE_MESSAGE’,
    RECEIVE_RAW_CREATED_MESSAGE: ‘RECEIVE_RAW_CREATED_MESSAGE’,
    RECEIVE_RAW_MESSAGES: ‘RECEIVE_RAW_MESSAGES’
  })
};

actions/ChatServerActionCreators.js

var ChatAppDispatcher = require('../dispatcher/ChatAppDispatcher');
var ChatConstants = require('../constants/ChatConstants');

var ActionTypes = ChatConstants.ActionTypes;

module.exports = {
  receiveAll: function(rawMessages) {
    ChatAppDispatcher.dispatch({
      type: ActionTypes.RECEIVE_RAW_MESSAGES,
      rawMessages: rawMessages
    });
  }
};

dispatcher/ChatAppDispatcher.js

var Dispatcher = require('flux').Dispatcher;
module.exports = new Dispatcher();

stores/MessageStore.js

var ChatAppDispatcher = require('../dispatcher/ChatAppDispatcher');
var ChatConstants = require('../constants/ChatConstants');
var ChatMessageUtils = require('../utils/ChatMessageUtils');
var EventEmitter = require('events').EventEmitter;
var ThreadStore = require('../stores/ThreadStore');
var assign = require('object-assign');

var ActionTypes = ChatConstants.ActionTypes;
var CHANGE_EVENT = 'change';

var _messages = {};

function _addMessages(rawMessages) {
  rawMessages.forEach(function(message) {
    if (!_messages[message.id]) {
      _messages[message.id] = ChatMessageUtils.convertRawMessage(
        message,
        ThreadStore.getCurrentID()
      );
    }
  });
}

function _markAllInThreadRead(threadID) {
  for (var id in _messages) {
    if (_messages[id].threadID === threadID) {
      _messages[id].isRead = true;
    }
  }
}

var MessageStore = assign({}, EventEmitter.prototype, {

  emitChange: function() {
    this.emit(CHANGE_EVENT);
  },

  /**
   * @param {function} callback
   */
  addChangeListener: function(callback) {
    this.on(CHANGE_EVENT, callback);
  },

  removeChangeListener: function(callback) {
    this.removeListener(CHANGE_EVENT, callback);
  },

  get: function(id) {
    return _messages[id];
  },

  getAll: function() {
    return _messages;
  },

  /**
   * @param {string} threadID
   */
  getAllForThread: function(threadID) {
    var threadMessages = [];
    for (var id in _messages) {
      if (_messages[id].threadID === threadID) {
        threadMessages.push(_messages[id]);
      }
    }
    threadMessages.sort(function(a, b) {
      if (a.date < b.date) { return -1; } else if (a.date > b.date) {
        return 1;
      }
      return 0;
    });
    return threadMessages;
  },

  getAllForCurrentThread: function() {
    return this.getAllForThread(ThreadStore.getCurrentID());
  }

});

MessageStore.dispatchToken = ChatAppDispatcher.register(function(action) {
  switch(action.type) {

    case ActionTypes.RECEIVE_RAW_MESSAGES:
      _addMessages(action.rawMessages);
      ChatAppDispatcher.waitFor([ThreadStore.dispatchToken]);
      _markAllInThreadRead(ThreadStore.getCurrentID());
      MessageStore.emitChange();
      break;

    default:
      // do nothing
  }
});

module.exports = MessageStore;

components/ThreadSection.react.js (finally we come up to a component. Hopefully we didn’t forget what we wanted to do here at the first place)

var React = require('react');
var ThreadListItem = require('../components/ThreadListItem.react');
var ThreadStore = require('../stores/ThreadStore');
var UnreadThreadStore = require('../stores/UnreadThreadStore');

function getStateFromStores() {
  return {

    currentThreadID: ThreadStore.getCurrentID(),
    unreadCount: UnreadThreadStore.getCount()
  };
}

var ThreadSection = React.createClass({

  getInitialState: function() {
    return getStateFromStores();
  },

  componentDidMount: function() {
    ThreadStore.addChangeListener(this._onChange);
    UnreadThreadStore.addChangeListener(this._onChange);
  },

  componentWillUnmount: function() {
    ThreadStore.removeChangeListener(this._onChange);
    UnreadThreadStore.removeChangeListener(this._onChange);
  },

  render: function() {
      // ...
    );
  },

  _onChange: function() {
    this.setState(getStateFromStores());
  }

});

module.exports = ThreadSection;

Do you see it? Massive amount of code for simple data manipulation. It may be useful for large-scale apps and long-term maintenance, but in most cases you don’t create large-scale apps. In fact component-based architecture should encourage to do multiple simple small-scale components independent from rest of the application.

Flux is super hyped because Facebook developers use it with React. You won’t see any alternatives on Facebook Developers’ YouTube channel. After a few hours of reaserch in React/Flux documentation, forums, Stack Overflow and reactiflux.com I felt like the only choice I have is: which Flux implementation should I use with my app? Fortunately you are not stuck in the React-ecosystem!

React.js - You Might Not Need Flux

What alternatives are there?

In fact there are many alternatives.

When using React+Backbone you’ve got everything set: Just bind the model/collection `change` event and you’re ready to go. When your model or collection is singleton accessible from any child component, it’ll be much easier to use than creating a custom action type, store and dispatch it like flux does.

When you’re using React+Angular: $emit/$broadcast in model/collection and listen in react component by $on. Dead simple.

Using Backbone, Angular or any other full-framework with Reacts’ View layer solves lots of other problems like: Handling ajax, routing, model validation etc. Avoid reinventing the wheel.

Other data-flow approaches worth to mention and further research:

Read later:

Questions, suggestions? Leave your comments below.

by Cezary Nowak, Front-end Developer
  • Brennan Smith

    You could also consider something based on RxJS such as Cycle JS (http://cycle.js.org/) and Yolk (https://github.com/garbles/yolk), since React/Flux are kind of based on Reactive Programming principles anyway and you might as well try something that tries to stick to that paradigm.

    Or you could consider something like Snow Flux (https://github.com/modesty/snow-flux) or Luna (https://github.com/escherpad/luna), if you want to stick with React but still get some of the benefits of RxJS/Observables, etc.

    • Cezary Daniel Nowak

      @Brennan Smith thank you for your reply. CycleJS and RxJS are definitely worth to try 🙂

  • Osazeme Usen

    I am currently at a crossroad of learning a frontend framework. I was considering reactjs, but this article threw more light on how I should learn something else together with reactjs. I know this article isn’t about which technology to learn. I just need your honest advice. Do you still think the learning curve of reactjs is steeper than that of angularjs?

    • rwoody89

      React is easier. You can start building complex components today, very easily, without flux. Flux is a great way to tie together MANY components of an application in a way that makes it easy to reason about state, etc.

      Learn to make great React components (dig in, it’s not too hard!), and save your mega-single-page-sso-enabled app for once you have mastered React components.

      Sincerely,

      Someone who didn’t “get” React at all 6 months ago. Now professional.

      • Osazeme Usen

        thanks

you may also like these posts

Frontend and JavaScript Resources for Back-end Developers

Will Vue.js Become a Giant Like Angular or React?

11 Biggest Takeaways for iOS Developers from WWDC 2017

SUBSCRIBE TO OUR NEWSLETTER

Get the latest info about technology, design, product management (and some snaps from 10Clouds life) - subscribe to our newsletter.