Menu Search
Jump to the content X X
Smashing Conf New York

You know, we use ad-blockers as well. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. our upcoming SmashingConf New York, dedicated to smart front-end techniques and design patterns.

Qualities Of Good Flux Implementations

It has been an exciting year for my team. Last year we kicked off a project using React71, and over the course of the project we’ve learned a lot about React and Flux2 — Facebook’s recommended architectural principles for React apps. In this article, we’ll take a look at some of the key lessons we’ve learned.

Whether you’re new to React and Flux, or going as far as building your own Flux implementation, I think you’ll not only enjoy this journey with us, but find some thought-provoking questions and wisdom you can apply in your own endeavors.

Further Reading on SmashingMag

Helpful Background Link

This post assumes you have some level of familiarity with React and Flux. Already familiar with them? Feel free to skip to “Introducing Lux.js” section. Otherwise, I recommend reading through the links below.

React Link

React71 is an open-source JavaScript library, maintained mainly by Facebook, and intended to be used in large applications that use data that changes over time. Obviously this is especially helpful when developing single-page applications. If you’re familiar with the model-view-controller pattern, React is considered to be only the view, handling the user interface in an app, and can be used in conjunction with other JavaScript libraries or larger MVC frameworks. Here’s a high level summary of React:

  • React focuses on view concerns, and does not attempt to be an “everything framework”
  • React UIs are built out of components.
  • React components can be written using JSX8 — an XML-based extension to JavaScript — or with plain JavaScript.
  • React components render to a virtual DOM. Subsequent renders are “diffed” with the previous render, and the minimum number of DOM mutations are executed to effectively patch the DOM to bring it up to date.

Check out Facebook’s Getting Started9 guide.

Flux Link

Flux10 is an architectural pattern recommended by Facebook for building apps with React. Whereas React’s opinions nudge you towards unidirectional data flow, Flux provides a fuller picture as to what that actually looks like. Several Flux implementations have arisen (LeanKit’s lux.js11, included), providing a fascinating insight into how different teams are tackling the challenges they face. A high-level summary of Flux would include:

  • Flux apps have three main abstractions: views (React components), stores, and the dispatcher.
  • Views “propagate” actions (e.g. user interaction) through the dispatcher.
  • The dispatcher handles notifying the various stores of the action.
  • If a store’s state changes, it emits a change event, and views depending on that store for state will rerender.

Check out Facebook’s overview of Flux12.

Introducing Lux.js Link

JavaScript developers crank out new frameworks as fast as a politician making promises at a campaign rally. Why, then, write another framework? I love this subject, though it falls outside the scope of this article. Lux.js13 is an implementation of the Flux architecture using React; we’ve tailored it to fit our team’s specific set of needs, skills and goals. In fact, our work with lux attempts to strike a delicate balance between consistent opinions and flexibility to include other libraries that best solve the problem at hand.

Over time, failing and succeeding in quite a few projects, we’ve found the following qualities to be the drivers of success in our own flux implementation:

  1. Don’t get in React’s way.
  2. Continuously eliminate boilerplate.
  3. Treat every input as an action.
  4. Store operations must be synchronous.
  5. Make it easy to play well with non-lux/non-React instances.

Examples Link

Dmitri Voronianski created flux-comparison14, which lets you see a side-by-side comparison of several flux variants (using a basic shopping cart example). I’ve implemented the same example using lux to help illustrate the explanations along the way. I highly recommend checking this project out — it’s a great way to quickly familiarize yourself with several leading Flux implementations.

OK, with all that out of the way, let’s look closer at the qualities I mentioned above.

Staying Out Of The Way Link

React does a great job at focusing only on what it aims to solve. By not being prescriptive on broader things like remote data communications (HTTP, WebSockets), and by providing hooks that enable you to incorporate non-React UI libraries, React gives you the opportunity to assemble the tools that best address the needs of your app. Just as React stays out of the way of concerns it doesn’t solve for, we’ve found it’s equally important to stay out of React’s way. It’s easy to get in the way as you begin abstracting common patterns in how you use another library/framework behind your own API. (Note: this isn’t always a bad thing!) For example, let’s look at the common component behaviors we’ve built into lux, and how our usage of them has evolved.

Controller Views Link

You will often hear React developers refer to controller views — a React component that typically sits at or near the top of a section of the page, which listens to one or more stores for changes in their state. As stores emit change events, the controller view updates with the new state and passes changes down to its children via props.

lux provides a controllerView method that gives you back a React component capable of listening to lux stores. Under the hood, lux uses mixins to give the React components different behaviors, and the controllerView method gives a component both a store mixin (making it capable of listening to stores), and an ActionCreator mixin (making it capable of publishing actions). For example:

var CartContainer = lux.controllerView({

  getActions: [ "cartCheckout" ],

  stores: {
    listenTo: [ "cart" ],
    onChange: function() {
      this.setState(getStateFromStores());
    }
  },

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

  onCheckoutClicked: function () {
    var products = this.state.products;
    if (!products.length) {
      return;
    }
    this.cartCheckout(products);
  },

  render: function () {
    return (
      <Cart products={this.state.products} total={this.state.total} onCheckoutClicked={this.onCheckoutClicked} />
    );
  }
});

While we still like this convenient approach, we’ve found ourselves moving to the alternative approach of setting up a plain React component, and passing the lux mixins necessary to achieve the same result. Note that here we’re calling React.createClass and using the mixins option:

var CartContainer = React.createClass({

  mixins: [ lux.reactMixin.store, lux.reactMixin.actionCreator ],

  getActions: [ "cartCheckout" ],

  stores: {
    listenTo: [ "cart" ],
    onChange: function() {
      this.setState(getStateFromStores());
    }
  },

  // other methods, etc.
});

Either approach is valid, though we feel the second approach is more out of React’s way. Why?

  • We get a component’s displayName for free (as the JSX transformer will use our var name when it sees React.createClass).
  • Some controller views don’t need to be ActionCreators. The second approach means we could only pass the store mixin in those cases, keeping concerns focused. The first approach always gives the component both mixins, even if not used.
  • There’s no need to explicitly pass the React instance to lux (done via lux.initReact( React )) so that it knows how to create components.

Note: Why spend time explaining these two different approaches? It’s about staying out of React’s way. We can easily fall prey to either over- or underabstracting, thus we need to give ourselves room to adapt as our understanding improves. The evolution of our approach over time has been informed as we’ve asked ourselves what makes a good flux implementation. This process of continually questioning and evaluating is a vital part of the life of any library or framework.

Boilerplate Elimination Link

In our experience, adopting React and Flux has moved infrastructure and framework concerns into the background so we can focus on actually creating features for our app. Still, there are annoying bits of code that tend to crop up a lot. For example, consider this common approach to wiring/unwiring components to listen to store change events:

// Taken from the facebook-flux example:
// https://github.com/voronianski/flux-comparison/blob/master/facebook-flux/js/components/CartContainer.jsx
var CartContainer = React.createClass({
  // only showing the methods we're interested in

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

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

  // more methods, etc.
});

Honestly, the boilerplate tax isn’t high here, but it’s still present. Since mixins can provide component life cycle methods, we made this automatic when you include lux mixins:

var ProductsListContainer = React.createClass({

  mixins: [ lux.reactMixin.store ],

  stores: {
    listenTo: [ "products" ],
    onChange: function() {
      this.setState(getAllProducts());
    }
  },

  // more methods, etc.
});

When our ProductsListContainer stands up, it will be ready to listen to any of the store namespaces provided in the stores.listenTo array, and those subscriptions will be removed if the component unmounts. Goodbye boilerplate!

ActionCreator Boilerplate Link

In Flux apps, you’ll usually see dedicated ActionCreator modules like this:

// snippet from: https://github.com/voronianski/flux-comparison/blob/master/facebook-flux/js/actions/ActionCreators.js
var ActionsCreators = exports;

ActionsCreators.receiveProducts = function (products) {
  AppDispatcher.handleServerAction({
    type: ActionTypes.RECEIVE_PRODUCTS,
    products: products
  });
};

ActionsCreators.addToCart = function (product) {
  AppDispatcher.handleViewAction({
    type: ActionTypes.ADD_TO_CART,
    product: product
  });
};

As we regularly asked what repeated code we could eliminate and replace with convention, ActionCreator APIs kept coming up. In our case, we use postal.js15 for communication between ActionCreators and the dispatcher (postal is an in-memory message bus library, providing advanced publish/subscribe functionality). 99.9% of the time, an ActionCreator method published an action message with no additional behavior. Things evolved over time like this:

// The very early days
// `actionChannel` is a ref to a postal channel dedicated to lux Actions
var ActionCreators = {
  addToCart: function() {
    actionChannel.publish( {
      topic: "execute.addToCart",
      data: {
        actionType: ActionTypes.ADD_TO_CART,
        actionArgs: arguments
      }
    } );
  }
};

That was very quickly abstracted into an ActionCreator mixin to enable this:

// The early-ish days
var ActionCreators = lux.actionCreator({
  addToCart: function( product ) {
    this.publishAction( ActionTypes.ADD_TO_CART, product );
  }
});

You’ll notice two things in the code above: first, the use of lux.actionCreator, which mixes lux.mixin.actionCreator into the target; and second, the publishAction method (provided by the mixin).

At the same time we were using the above mixin approach, we’d fallen into the practice of having matching handler names on our stores (the handler method name matched the action type). For example, here’s a lux store that handles the addToCart action:

var ProductStore = new lux.Store( {

  state: { products: [] },

  namespace: "products",

  handlers: {
    addToCart: function( product ) {
      var prod = this.getState().products.find( function( p ) {
          return p.id === product.id;
      } );
      prod.inventory = prod.inventory > 0 ? prod.inventory - 1 : 0;
    }
  },

  // other methods, etc.
} );

Matching action type names and store handler names made conventional wire-up very simple, but we saw another area where we could eliminate boilerplate: if 99% of our ActionCreator API implementations just published a message, why not infer creation of ActionCreator APIs based on what gets handled by stores? So we did, while still allowing custom implementations of ActionCreator methods where needed. For example, when the store instance in the snippet above is created, lux will see that it handles an addToCart action. If an ActionCreator API hasn’t already been defined for this action under lux.actions, lux will create one, with the default behavior of publishing the action message.

Taking this approach means our components can specify what ActionCreator methods they want in an à-la-carte style. In this next snippet, our ProductItemContainer is using the lux.reactMixin.actionCreator mixin, which looks for a getActions array, and provides the specified actions as top level methods on the component. You can see we’re using the addToCart ActionCreator method in the onAddToCartClicked handler method.

var ProductItemContainer = React.createClass({

  mixins: [ lux.reactMixin.actionCreator ],

  getActions: [ "addToCart" ],

  onAddToCartClicked: function () {
    this.addToCart(this.props.product);
  },

  render: function () {
    return (
      <ProductItem product={this.props.product} onAddToCartClicked={this.onAddToCartClicked} />
    );
  }
});

As with any convention, there are trade-offs. Composition is an important aspect of ActionCreator APIs. They should be modeled separate from the component(s) that use them. So far, we believe this approach upholds that, while trading some of the explicit nature (e.g. keeping ActionCreators in their own module) for flexibility and terseness.

Everything Is An Action Link

Since this behavior of providing ActionCreator APIs was abstracted into a mixin, it made it possible for both React components as well as non-lux/React instances to use the mixin. My team has been taking advantage of this when it comes to things like remote data APIs. We’re using a hypermedia client called halon16, which understands how to consume our hypermedia resources using an extended version of HAL17 (Hypermedia Application Language, an open specification for defining the structure of HTTP resources). Covering hypermedia is beyond the scope of this article, but a number of good resources18 exist19 if you’re interested in learning more. Our client-side wrapper for halon uses lux’s actionCreator and actionListener mixins so that it can not only publish actions, but also handle them.

We approach it this way because we believe every input — whether it be user input or queued asynchronous execution (via Ajax, postMessage, WebSockets, etc.) — should be fed into the client as an action. If you’ve kept up with any of the React discussions over time, you might be thinking, “Jim, Facebook is OK with calling dispatch directly on an XHR response, rather than use another ActionCreator”. Absolutely — and that makes perfect sense when your implementation gives your util modules (like remote data APIs) a handle to the dispatcher. With lux, we opted for the gateway to the dispatcher to be via message contract, and removed the need for the dispatcher to be a dependency of any module.

So if every input is an action, this means we might have actions in our system that none of our stores care about. Other actions might be of interest to both a store and our remote data API. The value of how this complements and forces you into the pit of unidirectional data flow success can be illustrated in this image:

Unidirectional data flow in lux.js20

Unidirectional data flow in lux.js. (View large version21)

In the above scenario, a user clicked a button on the page that resulted in a server request. When the server responds, the response is published as a new action. While we know that the two actions are related, modeling things this way reinforces the avoidance of cascading updates, and it means your app’s behavior will be capable of handling data being pushed to it, not just pulled through HTTP requests.

What if we wanted to update the UI to reflect that data is loading? It’s as easy as having the appropriate store handle the same action:

Unidirectional data flow in lux.js.22

Unidirectional data flow in lux.js: Update the UI. (View large version23)

Another benefit of treating every input as an action: it makes it easy to see what behaviors are possible in your app. For example, here’s the output of calling lux.utils.printActions():

Unidirectional data flow in lux.js24

Unidirectional data flow in lux.js: Output of calling lux.utils.printActions(). (View large version25)

Lux also provides a utility method to view what stores would participate in handling an action, and in what order: lux.utils.printStoreDepTree(actionName):

Unidirectional data flow in lux.js26

Unidirectional data flow in lux.js: lux.utils.printStoreDepTree(actionName). (View large version27)

Lux + Ajax Examples Link

We’ve resisted any temptation to be too prescriptive when it comes to how you should interact with remote endpoints in lux. The main guideline we follow is to wrap your remote access in a developer-friendly API in the client (rather than scatter Ajax requests throughout the codebase!), and make that API wrapper an ActionListener and ActionCreator. For example, let’s look at a couple of conceptual approaches you can take:

Plain Ajax Link

The example below only shows the relevant portions of each piece. Our component publishes an action message for the cartCheckout action, and our WebApi wrapper listens for it. Notice that our response handler for the Ajax call actually publishes a new action message:

// in a CartContainer.jsx module
var CartContainer = React.createClass({
  // other methods, properties, etc.

  onCheckoutClicked: function() {
    var products = this.state.products;
    if (!products.length) {
      return;
    }
    this.cartCheckout(products);
  }
});

// In a WebApi.js module
var webApi = lux.actionCreatorListener({
  handlers: {
    cartCheckout: function(products) {
      $.ajax({
        url: "cart/checkout",
        method: "POST",
        data: products
      }).then(
        function(data) {
          this.publishAction("successCheckout", data);
        }.bind(this),
        cartErrorHandler
      );
    }
  }
});
How We Use halon Link

One of the many things we’ve grown to love about hypermedia resources is the built-in discoverability. Instead of having to hard-code specific links (as in the example above), halon allows us to follow links returned with resources, so the only URL we have to know is where we go to get the OPTIONS. In this approach, our WebApi module initializes halon (which results in an OPTIONS request to the server), and the resulting instance will contain the top-level resources we can act on, with their “actions” exposed as methods. In this case we have a cart resource that exposes a checkout action:

// in a CartContainer.jsx module
var CartContainer = React.createClass({
  // other methods, properties, etc.

  onCheckoutClicked: function() {
    var products = this.state.products;
    if (!products.length) {
      return;
    }
    this.cartCheckout(products);
  }
});

// In a WebApi.js module
var hal = halon( {
  root: "https://some-server.com/api",
  adapter: halon.jQueryAdapter( $ ),
  version: 1
} );
var webApi = lux.actionCreatorListener({
  handlers: {
    cartCheckout: function(products) {
      hal.cart.checkout(products)
        .then(
          function(data) {
            this.publishAction("successCheckout", data);
          }.bind(this),
          cartErrorHandler
        );
    }
  }
});

Stores And Synchronicity Link

Actions, Stores And Remote Data I/O Link

I believe a classic pitfall to those rolling their own Flux implementations is putting remote data I/O in stores. In the first version of lux, I not only fell into this pit, I pulled out a golden shovel and dug even deeper. Our stores had the ability to make HTTP calls — and as a result, the need for action dispatch cycles to be asynchronous was unavoidable. This introduced a ripple of bad side effects:

  • Retrieving data from a store was an asynchronous operation, so it wasn’t possible to synchronously use a store’s state in a controller ciew’s getInitialState method.
  • We found that requiring asynchronous reads of store state discouraged the use of read-only helper methods on stores.
  • Putting I/O in stores led to actions being initiated by stores (e.g. on XHR responses or WebSocket events). This quickly undermined the gains from unidirectional data flow. Flux stores publishing their own actions could lead to cascading updates — the very thing we wanted to avoid!

I think the temptation to fall into this pit has to do with the trend of client-side frameworks to date. Client-side models are often treated as write-through caches for server-side data. Complex server/client synchronization tools have sprung up, effectively encouraging a sort of two-way binding across the server/client divide. Yoda said it best: you must unlearn what you have learned.

About the time I realized I’d be better off making lux stores synchronous, I read Reto Schläpfer’s post “Async requests with React.js and Flux, revisited28”. He had experienced the same pain, and the same realization. Making lux stores synchronous, from the moment the dispatcher begins handling an action to the moment stores emit change events, made our app more deterministic and enabled our controller views to synchronously read store state as they initialized. We finally felt like we’d found the droids we were looking for.

Let’s take a look at one of the lux stores in the flux-comparison example:

var CartStore = new lux.Store( {
  namespace: "cart",

  state: { products: { } },

  handlers: {
    addToCart: {
      waitFor: [ 'products' ],
      handler: function( product ) {
        var newState = this.getState();
        newState.products[ product.id ] = (
          newState.products[ product.id ] ||
          assign( products.getProduct( product.id ), { quantity: 0 } )
        );
        newState.products[ product.id ].quantity += 1;
        this.setState( newState );
      }
    },
    cartCheckout: function() {
      this.replaceState( { products: {} } );
    },
    successCheckout: function( products ) {
      // this can be used to redirect to success page, etc.
      console.log( 'YOU BOUGHT:' );
      if ( typeof console.table === "function" ) {
        console.table( products );
      } else {
        console.log( JSON.stringify( products, null, 2 ) );
      }
    }
  },

  getProduct: function( id ) {
    return this.getState().products[ id ];
  },

  getAddedProducts: function() {
    var state = this.getState();
    return Object.keys( state.products ).map( function( id ) {
      return state.products[ id ];
    } );
  },

  getTotal: function() {
    var total = 0;
    var products = this.getState().products;
    for (var id in products) {
      var product = products[ id ];
      total += product.price * product.quantity;
    }
    return total.toFixed( 2 );
  }
} );

A lux store contains (at least) a handlers property and a namespace. The names of the keys on the handlers property match the action type that they handle. In keeping with Flux principles, it’s possible for lux stores to wait on other stores before executing their handler. The stores you need to wait on can be specified on a per-action basis. The addToCart handler above is a good example. In the waitFor array, you specify the namespaces of any other store you need to wait on — this handler waits on the “products” store. The dispatcher determines the order in which stores need to execute their handlers at runtime, so there’s no need to worry about managing the order yourself in your store logic. (Note that if you don’t need to wait on any other stores, the handler value can be just the handler function itself rather than the object literal representation on addToCart above.)

You can also set initial state on the store, as we’re doing above, and provide top-level methods that are used for reading data (the lux store prototype provides the getState() method). Since store handlers execute synchronously, you can safely read a store’s state from any component’s getInitialState method, and you can be assured that no other action will interrupt or mutate store state while another action is being handled.

lux stores also provide setState and replaceState methods, but if you attempt to invoke them directly, an exception will be thrown. Those methods can only be invoked during a dispatch cycle; we put this rather heavy-handed opinion in place to reinforce the guideline that only stores mutate their own state, and that’s done in a handler.

Plays Well With Others Link

Another key lesson for our team: it needs to be simple for lux and non-React/non-lux (external) instances to play well together. To that end, lux provides mixins that can be used by external instances.

Store Mixin Link

The store mixin enables you to listen for store change events. For example, this snippet shows an instance that’s wired to listen to our ProductStore and CartStore:

var storeLogger = lux.mixin({
  stores: {
    listenTo: [ "products", "cart" ],
    onChange: function() {
      console.log( "STORE LOGGER: Received state change event" );
    },
  }
}, lux.mixin.store);

ActionCreator Mixin Link

The actionCreator mixin gives the instance a publishAction( actionName, arg1, arg2…) method. This method handles packaging the metadata about the action into a message payload and then publishes it (if you’ve created a custom ActionCreator that does more than just publish the action message, it will invoke that behavior):

// calling lux.actionCreator is a convenience wrapper around
// lux.mixin( target, lux.mixin.actionCreator );
var creator = lux.actionCreator( {
  doAThing: function() {
    this.publishAction( "doJazzHands", "hey, I can lux, too!", true, "story" );
  }
} );

ActionListener Mixin Link

The actionListener mixin wires the instance into postal, so that it listens for any lux action messages. When a message arrives, it checks the handlers property for a matching handler and invokes it:

var listener = lux.actionListener({
  handlers: {
    doJazzHands: function(msg, someBool, lastArg) {
      console.log(msg, someBool, lastArg); // -> hey, I can lux, too! true story
    }
  }
});

Why Not Both? Link

It’s not uncommon — especially if remote data API wrappers are involved — to need both actionCreator and actionListener mixins. lux provides a convenience method for this, unsurprisingly named actionCreatorListener. In the flux-comparison example, the wrapper around the mock remote data API uses this:

// WebAPIUtils.js
var shop = require( '../../../common/api/shop' );
var lux = require( 'lux.js' );

module.exports = lux.actionCreatorListener( {
  handlers: {
    cartCheckout: function( products ) {
      shop.buyProducts( products, function() {
        this.publishAction( "successCheckout", products );
      }.bind( this ) );
    },
    getAllProducts: function() {
      shop.getProducts( function( products ) {
        this.publishAction( "receiveProducts", products );
      }.bind( this ) );
    },
  }
} );

The above module listens for the cartCheckout and getAllProducts actions. As it handles them, it uses the publishAction method (simulating how a server response would initiate a new Action).

So far, the mixins have covered every need we’ve had to make non-lux/non-React instances play well with lux. If those weren’t enough, though, the underlying message contracts for actions and store update notifications are very simple, and could serve as an alternative. In fact, we plan to use those in some future Chrome dev tools extensions for lux.

Wrapping Up Link

As I’ve looked through other Flux implementations, I’ve been encouraged to see that these principles are frequently present in them as well. The number of options available can feel overwhelming, but overall I find it an encouraging development. Solid and successful patterns like Flux will, by their very nature, encourage multiple implementations. If our experience is any indication, keeping these principles in mind can help guide you as you select, or write, the Flux implementation you need.

(rb, ml, og)

Footnotes Link

  1. 1 http://facebook.github.io/react/
  2. 2 http://facebook.github.io/react/blog/2014/05/06/flux.html
  3. 3 https://www.smashingmagazine.com/2016/09/how-to-scale-react-applications/
  4. 4 https://www.smashingmagazine.com/2016/04/consider-react-native-mobile-app/
  5. 5 https://www.smashingmagazine.com/2017/02/a-detailed-introduction-to-webpack/
  6. 6 https://www.smashingmagazine.com/2015/05/client-rendered-accessibility/
  7. 7 http://facebook.github.io/react/
  8. 8 http://facebook.github.io/react/docs/jsx-in-depth.html
  9. 9 http://facebook.github.io/react/docs/getting-started.html
  10. 10 https://facebook.github.io/flux/
  11. 11 https://github.com/LeanKit-Labs/lux.js
  12. 12 http://facebook.github.io/flux/docs/overview.html#content
  13. 13 https://github.com/LeanKit-Labs/lux.js
  14. 14 https://github.com/voronianski/flux-comparison
  15. 15 https://github.com/postaljs/postal.js
  16. 16 https://github.com/LeanKit-Labs/halon
  17. 17 https://tools.ietf.org/html/draft-kelly-json-hal-06
  18. 18 http://martinfowler.com/articles/richardsonMaturityModel.html
  19. 19 http://phlyrestfully.readthedocs.org/en/latest/halprimer.html
  20. 20 https://www.smashingmagazine.com/wp-content/uploads/2015/05/01-luxdataflow1-opt.png
  21. 21 https://www.smashingmagazine.com/wp-content/uploads/2015/05/01-luxdataflow1-opt.png
  22. 22 https://www.smashingmagazine.com/wp-content/uploads/2015/05/02-luxdataflow2-opt.png
  23. 23 https://www.smashingmagazine.com/wp-content/uploads/2015/05/02-luxdataflow2-opt.png
  24. 24 https://www.smashingmagazine.com/wp-content/uploads/2015/05/03-luxPrintActions-opt.png
  25. 25 https://www.smashingmagazine.com/wp-content/uploads/2015/05/03-luxPrintActions-opt.png
  26. 26 https://www.smashingmagazine.com/wp-content/uploads/2015/05/04-luxPrintStoreDepTree-opt.png
  27. 27 https://www.smashingmagazine.com/wp-content/uploads/2015/05/04-luxPrintStoreDepTree-opt.png
  28. 28 http://www.code-experience.com/async-requests-with-react-js-and-flux-revisited/

↑ Back to top Tweet itShare on Facebook

Jim Cowart is tragically geeky about JavaScript & open source development...but he's not a fan of lists, so we'll stop there. Having journeyed through Cold Fusion, an obscure proprietary JavaScript BI implementation, C#, a smidgen of Erlang and even some time as a data warehouse architect and developer (apparently he lied to us about not liking lists), he's most passionate about connecting with other developers – learning, sharing and promoting patterns and ideas that will make development more productive, enjoyable and empowering. Jim works at LeanKit as their Web Architect & Web Team Lead and lives in Chattanooga, TN with his wife and three sons.

  1. 1

    Aamir Afridi

    June 22, 2015 7:12 pm

    This article is more about LUX. disappointed.
    ps saying this as a newreaxt/flux learner

    9
  2. 2

    I came here to find a solid article that compares various of flux implementations and what do we get? A sponsored article about lux, from the lux author. Of course you’re going to praise your damned library but god, did this post slip through the moderation queue? This is no where near the quality that we expect from smashingmagazine.

    10
    • 3

      John – Thank you for the feedback. I’m sorry the article didn’t cover what you expected. The goal was to discuss the way we’d evolved our approach on my team over time – focusing on what had and hadn’t worked. In conversations I’ve had with other developers coming to React/Flux, I’ve found many (like my team) were very interested in seeing concrete examples of how they were using React (and whatever flux variant) along side other libs (esp communications-related) as well as how stores fit into the flow of remote data. My intent was to talk through the five high level points from both a philosophical standpoint (which we believe can apply to any flux implementation) without skipping over concrete examples to prove the reasoning. Since we use lux, it didn’t make sense to not talk through it from that perspective. Lux is maintained by a team – of which I am a part – I certainly wouldn’t claim credit for it being “mine”. I mentioned Dmitri’s flux-comparison repo early on in the post because I think he’s done a fantastic job providing a simple way to compare various implementations. There are a lot of great choices.

      2
    • 4

      Vitaly Friedman

      June 22, 2015 8:43 pm

      We never publish sponsored posts, John. This article is covering the open-sourced library and an implementation and features a case study on how it was built. An article on various Flux implementations is coming.

      2
  3. 5

    I have made a few components with react and am yet to read an article that exlains why react is so good with some simple clear examples and explanations. Sure I know it is a single direction closed loop data flow. Why is that more usefull than current methods? It forces you to make components? Why is that usefull? You can process it server side. Why is that usefull? It does blisteringly fast dom rendering? Where are the examples? Prove it. And so on and so on. Seems to me like no one really understands it and they are all just using it because everyone else is. It’s the latest in thing. There is a load of these little experiments out there and its great that people are trying out new things and ok I get it react is the view and people combine it with other frameworks. But …. what does it do better than current technology and why should anyone care? After reading this article I still don’t care about react. Yet another article acting as a nail in the coffin of my react interest. And as John said above this article was 10% React 90%Lux …. now if the combination of the 2 actually explained why I should bother learning flux or lux, I would have found either parts interesting. As a mobile mid level JS developer- Thanks for taking the time to talk about it, no doubt others will find some of this interesting. Now of course you can write what you like and I hope not to disuade you from what interests you. I would however like to see more examples here explaining the why “Insert post subject” is good. I need reasons to keep reading other than an opinion about a pattern or talking about what you did, not why you did it. /rant … sorry that could have been written more constructively i’m just a frustrated angry little man /ignore :D

    2
    • 6

      I’d say React has the potential to be great by reducing the insane amount of boilerplate code that Angular and Ember bring with them. With that in mind, the JSX syntax by itself appears like weird framework-only crap, but it’s easy to get used to, I found. It just makes your app much more readable and easier to setup for other prospective clients. I’m using a home-made Yeoman setup for my base project and each module.

      I’m still not sure why Flux is “better” than a pub/sub system like Postal.js, but they claim that Flux allows you to handle these events in a specific order, which gives the developer more control over everything that happens.

      The fast DOM rendering isn’t true. Other frameworks are faster. It’s just that React updates only the DOM elements that need to be updated, whereas I found with other frameworks it was easy to fall victim to the “update entire screen” issue when only 1 variable was changed; should’ve updated 3 spans, not the entire page. React does this beautifully, natively.

      I’m from the era where XML and XSLT were the front-end templating solution by choice for many. The JSX-way of typing components out in HTML and the sensible way it all fits together makes my code very, very easy to read and maintain.

      I’ve been rewriting my company’s web-project from Ember to React and it’s already much smaller in size, much more efficient in the browser in the sense of user experience, and generally feels like a breeze to work with. I am not sure about Lux, but they did tackle a few things that make React and Flux confusing to work with.

      1
      • 7

        Mahade – thanks so much for reading! Glad to hear you’re having a good experience with React in general. As far as whether or not flux is better than a pub/sub system like Postal.js – of course it could depend on a lot of things. In our case, lux is using postal under the hood, but we’re enforcing a unidirectional flow which we’ve found has really helped eliminate cascading/side-effect updates I’ve observed in other apps that take more traditional pub-sub approach that doesn’t enforce a direction of flow. React’s DOM diffing is fast, but I never claimed it was the fastest :-). Having worked in many frameworks over the last 15 years that were easy traps for the “update entire screen” problem you described, I appreciate how React abstracted the concerns about only targeting what needs an update so that it’s out of my way as a developer…and that it’s performant in doing so.

        0
    • 8

      Dave – there’s actually a decent amount of content available relating to the questions you asked. I’d recommend finding some of Pete Hunt’s talks, and also check out the JSJabber podcast where he’s been a guest. React is certainly not alone in using a component-based model for UI. I’d argue the key areas it differs from other popular approaches are that it embraces a ‘re-render everything’ approach where components are akin to idempotent functions that always render the same UI given the same state every time (they aren’t exactly idempotent functions in React, but it feels dang close), and it encourages a unidirectional flow of data (the principles behind flux drive this point even deeper). That’s quite different from two-way data synchronization popular in other frameworks. My team cares about these things, because embracing the principles behind flux has given us the most testable client UI I’ve ever encountered & our app is predictable as we aren’t dealing with cascading side effects that two-way data sync scenarios can often expose. Having a well-tested app (> 97% coverage) that behaves in a consistently predictable fashion has unleashed a pace of innovation and feature development we weren’t experiencing before. I’m sorry you were frustrated by the discussion of flux/lux over react specifically. The goal of this post was to walk through my team’s journey of adopting a flux approach over the last year, and to be real about what worked and didn’t work for us and *why*. As I’ve talked with other developers writing apps with React (and especially the ones moving into flux), I consistently hear interest in concrete details. Given that our team wrote lux to help facilitate our work at LeanKit, it made sense to discuss lux, since it’s an integral part of our journey. The are plenty of good choices, not only in the “react/flux ecosystem” but beyond as well. I wish you the best in your own endeavors. :-)

      1
  4. 9

    nice one! great article! after having built a huge application with React, this approach looks good, smooth and clean.

    0
    • 10

      Thank you, Francesco! Glad you enjoyed it.

      0
      • 11

        Well, I enjoyed article (tutorial to Lux) too. This looks like very pleasant way to create large React apps. I like how mixins solve boilerplate bloat problem in your solution. Good work. Will definitely look into Lux in my own project.

        Can I have one question – how Lux plays with Immutable.js and pureRender mixin? Have you tried use those on your projects?

        Thanks Jim, awesome article.

        0
  5. 12

    kunalroy1245

    June 23, 2015 1:27 pm

    Send online gifts on Raksha Bandhan to your beloved brother that conveying the message of your heart. Send Rakhi Gifts to USA and gain appreciation for your choice. Order Online Rakhi Delivery in USA to make your beloved brother feels your presence.

    -12
  6. 13

    Geertjan Brits

    June 25, 2015 3:21 am

    So how does a store state actually get updated with new data coming from, say, a remote web Api? I’ve read the separate store and web-Api (actionCreatorListener) but struggle to see them in one flow/process.

    Thanks

    0
    • 14

      Geertjan – This image from the article might help frame the answer to your question: https://www.smashingmagazine.com/wp-content/uploads/2015/05/01-luxdataflow1-opt.png. The approach we’ve adopted treats everything as an Action, so the initial request to the remote web API is an action, and when the client processes the response, it’s published as another action. Stores that need to know about that Action would have a handler for it, and in a store’s handler you’d make whatever updates to the store’s state from the remote API response. I hope that helps!

      0
  7. 15

    Great post! I’ve recently developed an app with React. It’s quite fast. But my problem with it was that if u for example make an input to an input field, the entire component(in my case a form) had to update irself, which causes more javascript being executed so that ur browser will start lagging at some point. How do u fix that? If u build more child components u could probably get around that, but then i had the problem zhat the initial rendering was too slow

    3
  8. 16

    Shane Rogers

    June 28, 2015 8:27 am

    Hey my team recently open-sourced our React app for Sprint.ly. It’s a vanilla implementation of React + Flux and is a great example of a production R+F app.
    We also have pretty good test coverage, so its a perfect project to follow and learn patterns from :)

    If you have any feedback on it or the product, let us know on GitHub!

    https://github.com/sprintly/sprintly-kanban

    1
  9. 17

    Thank you for the step by step!.

    0

↑ Back to top