Tag Archives: frameworks

Creating Custom Inputs With Vue.js

Component-based libraries or frameworks such as Vue have given us the wonderful ability to create reusable components to be spread throughout their respective application, ensuring that they are consistent, and (hopefully) simplifying how they are used.

Creating Custom Inputs With Vue.js

In particular, form inputs tend to have plenty of complexity that you’d want to hide in a component, such as custom designs, labels, validation, help messages, and making sure each of these pieces are in the correct order so that they render correctly.

The post Creating Custom Inputs With Vue.js appeared first on Smashing Magazine.

View this article – 

Creating Custom Inputs With Vue.js

Which Responsive Design Framework Is Best? Of Course, It Depends.

In 2017, the question is not whether we should use a responsive design framework. Increasingly, we are using them. The question is which framework should we be using, and why, and whether we should use the whole framework or just parts of it.

Which Responsive Design Framework Is Best? Of Course, It Depends.

With dozens of responsive design frameworks available to download, many web developers appear to be unaware of any except for Bootstrap. Like most of web development, responsive design frameworks are not one-size-fits-all. Let’s compare the latest versions of Bootstrap, Foundation and UIkit for their similarities and differences.

The post Which Responsive Design Framework Is Best? Of Course, It Depends. appeared first on Smashing Magazine.

Continue at source: 

Which Responsive Design Framework Is Best? Of Course, It Depends.

Getting Started With Koa 2 And Async Functions

One of the upcoming features of JavaScript that I especially like is the support for asynchronous functions. In this article, I would like to show you a very practical example of building a server-side application using Koa 2, a new version of the web framework, which relies heavily on this feature.

Getting Started With Koa 2

First, I’ll recap what async functions are and how they work. Then, I’ll highlight the differences between Koa 1 and Koa 2. After that, I will describe my demo app for Koa 2, covering all aspects of development, including testing (using Mocha, Chai and Supertest) and deployment (using PM2).

The post Getting Started With Koa 2 And Async Functions appeared first on Smashing Magazine.

This article is from: 

Getting Started With Koa 2 And Async Functions

Battling BEM (Extended Edition): 10 Common Problems And How To Avoid Them


Whether you’ve just discovered BEM or are an old hand (in web terms anyway!), you probably appreciate what a useful methodology it is. If you don’t know what BEM is, I suggest you read about it on the BEM website before continuing with this post, because I’ll be using terms that assume a basic understanding of this CSS methodology.

Battling BEM (Extended Edition): 10 Common Problems And How To Avoid Them

This article aims to be useful for people who are already BEM enthusiasts and wish to use it more effectively or people who are curious to learn more about it. Now, I’m under no illusion that this is a beautiful way to name things. It’s absolutely not. One of things that put me off of adopting it for such a long time was how eye-gougingly ugly the syntax is. The designer in me didn’t want my sexy markup cluttered with dirty double-underscores and foul double-hyphens.

The post Battling BEM (Extended Edition): 10 Common Problems And How To Avoid Them appeared first on Smashing Magazine.

Link:

Battling BEM (Extended Edition): 10 Common Problems And How To Avoid Them

Write Your Next Web App With Ember CLI


When you start a fresh web project or start digging into an existing code base, chances are you’re trying to create or enhance a feature for your users. The last thing you want to do is spend time customizing build tools and creating infrastructure to develop your application. If you land a new client, you want to show them features today, not in a week after you’ve cobbled together a build pipeline.

Write Your Next Web App With Ember CLI

As you might already know, Ember is an “opinionated” JavaScript web framework focused on building ambitious, rich client web applications. Technologically, Ember has positioned itself as the antidote to hype fatigue. It’s a framework that just won’t die, but keeps pressing on with each innovation and with a commitment to backwards-compatibility.

The post Write Your Next Web App With Ember CLI appeared first on Smashing Magazine.

Link:

Write Your Next Web App With Ember CLI

Thumbnail

Sailing With Sails.js: An MVC-style Framework For Node.js


I had been doing server-side programming with Symfony 2 and PHP for at least three years before I started to see some productivity problems with it. Don’t get me wrong, I like Symfony quite a lot: It’s a mature, elegant and professional framework. But I’ve realized that too much of my precious time is spent not on the business logic of the application itself, but on supporting the architecture of the framework.

Sailing With Sails.js

I don’t think I’ll surprise anyone by saying that we live in a fast-paced world. The whole startup movement is a constant reminder to us that, in order to achieve success, we need to be able to test our ideas as quickly as possible. The faster we can iterate on our ideas, the faster we can reach customers with our solutions, and the better our chances of getting a product-market fit before our competitors do or before we exceed our limited budget. And in order to do so, we need instruments suitable to this type of work.

The post Sailing With Sails.js: An MVC-style Framework For Node.js appeared first on Smashing Magazine.

Continued here: 

Sailing With Sails.js: An MVC-style Framework For Node.js

Adopt framework thinking to be a marketing optimization leader

So, the other day, my 10-year-old daughter says to me, “Daddy, why do all the books you read say ‘Leadership’ on the front? Why is that all you read about?”

“Well,” I say, “leadership is one of the topics I’m learning more about this year.”

“But, why do you need to read books about it?” she continues, “Shouldn’t you be your own kind of leader? Why do you need to copy what other people say?”

My first thought: Who has been sneaking into the house and teaching this kid to be so smart?

My second thought: I hope she never stops asking questions like that.

My third thought: She’s right. Learning shouldn’t be an exercise in copying what’s worked for others. Their truths are only true for them. And my experiences and learning may only apply to my situation. I could meticulously copy the habits, attitudes and actions of Steve Jobs and end up a colossal failure. His leadership methods are probably not going to work for me.

On the other hand, there is huge value in learning what has worked for others, and in taking inspiration to find your own way.

That’s why Steve Jobs is part of my personal mentor wall, along with Edison, Ghandi, Picasso, Hitchens, Jim Carrey (for his vision and drive, not necessarily all his movies). Each one of them reminds me of a certain characteristic I want to remind myself of.

Mentors wall
My mentor’s wall

Each of them are multi-dimensional people and could inspire many different qualities, but they particularly inspired me in these areas:

  • Persistence – Thomas Edison
  • Influence – Mahatma Ghandi
  • Expression – Pablo Picasso
  • Intelligence – Christopher Hitchens
  • Vision – Jim Carrey
  • Boldness – Steve Jobs

Inspiration is a start and is important. The learning I gain from others is especially useful when they’ve assembled their knowledge into practical frameworks. Frameworks make their particular insights applicable to other situations.

What do you get from learning how others have solved problems?

  1. Inspiration. The more stories I discover about successful people, the more encouragement I feel that anything can be overcome.
  2. Frameworks for thinking about the challenges you’re facing. Thinking about problems from differing perspectives, and using different frameworks, teaches your brain to explore all possibilities.
  3. Discipline. Even though my kids think of “discipline” as a negative word, it’s clearly necessary for long-term success. Learning new frameworks stretches my mind and keeps it focused on the problems at hand, allowing the focused concentration time needed for my mind’s goal-striving mechanism (or as Maxwell Maltz refers to it in Psycho-Cybernetics, the Servo Mechanism) to lock onto a problem and seek a solution.

Great frameworks separate the pro from the amateur

People often ask me what makes WiderFunnel different than other optimization agencies. I was actually just asked that question again today.

And, while there are many possible answers: great clients, amazing team, high-performance culture, awesome results, years of experience, deep test archives, etc, one aspect stands out.

I made an important decision when we began as a purely Conversion Rate Optimization agency back in 2007. I decided that we would focus on developing framework thinking rather than assembling lists of tips and tricks.

To do that, we needed to learn what actually works through A/B testing, which meant that WiderFunnel would only take projects we could learn from by A/B testing everything.

This was the more difficult path than others have taken, but one I believed would produce better results and knowledge in the long term.

And it has worked.

We’ve run more tests than anyone and developed a more refined and robust process because we’ve focused on refining the process, not just on selling opinions. Selling opinions is easy. Testing and refining our own frameworks is hard.

You can use framework thinking in your work too

I love Sean Johnson’s article about using framework thinking. It’s a reminder that giving an opinion is easy; finding a list of tips and tricks to answer your question is easy. But, finding a framework to help you answer your question is more robust. It gives you an answer that doesn’t expire when one of the variables changes.

Search for frameworks to help you answer your questions and you’ll find a path to continued improvement.

Conversion optimization frameworks

In your conversion optimization work, you’ll likely need to answer questions such as:

  • Where should I test?
  • What should I test?
  • How does my audience perceive my product?

To answer questions like those (and more), WiderFunnel has developed frameworks to use within our optimization process. You can adopt and adapt these frameworks in your CRO work too.

Need to know where to target your test zone?
Use the PIE Framework for prioritizing tests.

PIE framework for A/B testing prioritization.
PIE framework for A/B testing prioritization.

Wondering why your visitors aren’t converting?
Use the LIFT Model to view your marketing touchpoints from their perspective. It has become the world’s most popular optimization hypothesis framework for a reason.

The LIFT Model
The LIFT Model

What is your most important value proposition to test?
Try brainstorming with the points of difference (PODs), points of parity (POPs), and points of irrelevance (POIs).

WiderFunnel PODs, POIs and POPs

The evolution of the best optimization process

As we continue to optimize high volume businesses, WiderFunnel’s process itself is also constantly being reviewed and optimized. We run quarterly projects with our whole team, called “focus areas”, to evolve how we operate to continuously add more value.

As a result, we now have a new process model to share! It’s called the Infinity Optimization Process™.

Infinity Optimization Process (TM)
WiderFunnel’s Infinity Optimization Process™

In the coming weeks, I will provide a more detailed explanation of this next generation of WiderFunnel’s system and how it will continue to deliver the best optimization results in the industry. Make sure you’re subscribed to the blog to get the updates on where we’re leading.

The post Adopt framework thinking to be a marketing optimization leader appeared first on WiderFunnel.

Read more: 

Adopt framework thinking to be a marketing optimization leader

Qualities Of Good Facebook’s React and Flux Implementations

It has been an exciting year for my team. Last year we kicked off a project using React31, 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.

Helpful Background

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

React31 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 JSX4 — 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 Started5 guide.

Flux

Flux6 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.js7, 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 Flux8.

Introducing Lux.js

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.js9 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

Dmitri Voronianski created flux-comparison10, 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

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

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 saying 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

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

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.js11 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

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 halon12, which understands how to consume our hypermedia resources using an extended version of HAL13 (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 good14 resources15 exist16 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.js17
Unidirectional data flow in lux.js. (View large version18)

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.19
Unidirectional data flow in lux.js: Update the UI. (View large version20)

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.js21
Unidirectional data flow in lux.js: Output of calling lux.utils.printActions(). (View large version22)

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.js23
Unidirectional data flow in lux.js: lux.utils.printStoreDepTree(actionName). (View large version24)

Lux + Ajax Examples

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

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

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

Actions, Stores And Remote Data I/O

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, revisited25”. 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 ]  )
        );
        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

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

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

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

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?

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

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

  1. 1 http://facebook.github.io/react/
  2. 2 http://facebook.github.io/react/blog/2014/05/06/flux.html
  3. 3 http://facebook.github.io/react/
  4. 4 http://facebook.github.io/react/docs/jsx-in-depth.html
  5. 5 http://facebook.github.io/react/docs/getting-started.html
  6. 6 https://facebook.github.io/flux/
  7. 7 https://github.com/LeanKit-Labs/lux.js
  8. 8 http://facebook.github.io/flux/docs/overview.html#content
  9. 9 https://github.com/LeanKit-Labs/lux.js
  10. 10 https://github.com/voronianski/flux-comparison
  11. 11 https://github.com/postaljs/postal.js
  12. 12 https://github.com/LeanKit-Labs/halon
  13. 13 https://tools.ietf.org/html/draft-kelly-json-hal-06
  14. 14 http://timelessrepo.com/haters-gonna-hateoas
  15. 15 http://martinfowler.com/articles/richardsonMaturityModel.html
  16. 16 http://phlyrestfully.readthedocs.org/en/latest/halprimer.html
  17. 17 http://www.smashingmagazine.com/wp-content/uploads/2015/05/01-luxdataflow1-opt.png
  18. 18 http://www.smashingmagazine.com/wp-content/uploads/2015/05/01-luxdataflow1-opt.png
  19. 19 http://www.smashingmagazine.com/wp-content/uploads/2015/05/02-luxdataflow2-opt.png
  20. 20 http://www.smashingmagazine.com/wp-content/uploads/2015/05/02-luxdataflow2-opt.png
  21. 21 http://www.smashingmagazine.com/wp-content/uploads/2015/05/03-luxPrintActions-opt.png
  22. 22 http://www.smashingmagazine.com/wp-content/uploads/2015/05/03-luxPrintActions-opt.png
  23. 23 http://www.smashingmagazine.com/wp-content/uploads/2015/05/04-luxPrintStoreDepTree-opt.png
  24. 24 http://www.smashingmagazine.com/wp-content/uploads/2015/05/04-luxPrintStoreDepTree-opt.png
  25. 25 http://www.code-experience.com/async-requests-with-react-js-and-flux-revisited/

The post Qualities Of Good Facebook’s React and Flux Implementations appeared first on Smashing Magazine.

Link to original:

Qualities Of Good Facebook’s React and Flux Implementations

Good Qualities Of Facebook’s React And Flux Implementations

It has been an exciting year for my team. Last year we kicked off a project using React31, 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.

Helpful Background

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

React31 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 JSX4 — 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 Started5 guide.

Flux

Flux6 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.js7, 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 Flux8.

Introducing Lux.js

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.js9 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

Dmitri Voronianski created flux-comparison10, 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

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

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 saying 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

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

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.js11 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

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 halon12, which understands how to consume our hypermedia resources using an extended version of HAL13 (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 good14 resources15 exist16 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.js17
Unidirectional data flow in lux.js. (View large version18)

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.19
Unidirectional data flow in lux.js: Update the UI. (View large version20)

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.js21
Unidirectional data flow in lux.js: Output of calling lux.utils.printActions(). (View large version22)

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.js23
Unidirectional data flow in lux.js: lux.utils.printStoreDepTree(actionName). (View large version24)

Lux + Ajax Examples

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

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

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

Actions, Stores And Remote Data I/O

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, revisited25”. 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 ]  )
        );
        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

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

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

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

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?

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

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

  1. 1 http://facebook.github.io/react/
  2. 2 http://facebook.github.io/react/blog/2014/05/06/flux.html
  3. 3 http://facebook.github.io/react/
  4. 4 http://facebook.github.io/react/docs/jsx-in-depth.html
  5. 5 http://facebook.github.io/react/docs/getting-started.html
  6. 6 https://facebook.github.io/flux/
  7. 7 https://github.com/LeanKit-Labs/lux.js
  8. 8 http://facebook.github.io/flux/docs/overview.html#content
  9. 9 https://github.com/LeanKit-Labs/lux.js
  10. 10 https://github.com/voronianski/flux-comparison
  11. 11 https://github.com/postaljs/postal.js
  12. 12 https://github.com/LeanKit-Labs/halon
  13. 13 https://tools.ietf.org/html/draft-kelly-json-hal-06
  14. 14 http://timelessrepo.com/haters-gonna-hateoas
  15. 15 http://martinfowler.com/articles/richardsonMaturityModel.html
  16. 16 http://phlyrestfully.readthedocs.org/en/latest/halprimer.html
  17. 17 http://www.smashingmagazine.com/wp-content/uploads/2015/05/01-luxdataflow1-opt.png
  18. 18 http://www.smashingmagazine.com/wp-content/uploads/2015/05/01-luxdataflow1-opt.png
  19. 19 http://www.smashingmagazine.com/wp-content/uploads/2015/05/02-luxdataflow2-opt.png
  20. 20 http://www.smashingmagazine.com/wp-content/uploads/2015/05/02-luxdataflow2-opt.png
  21. 21 http://www.smashingmagazine.com/wp-content/uploads/2015/05/03-luxPrintActions-opt.png
  22. 22 http://www.smashingmagazine.com/wp-content/uploads/2015/05/03-luxPrintActions-opt.png
  23. 23 http://www.smashingmagazine.com/wp-content/uploads/2015/05/04-luxPrintStoreDepTree-opt.png
  24. 24 http://www.smashingmagazine.com/wp-content/uploads/2015/05/04-luxPrintStoreDepTree-opt.png
  25. 25 http://www.code-experience.com/async-requests-with-react-js-and-flux-revisited/

The post Good Qualities Of Facebook’s React And Flux Implementations appeared first on Smashing Magazine.

Original post:

Good Qualities Of Facebook’s React And Flux Implementations

Qualities Of Good Flux Implementations

It has been an exciting year for my team. Last year we kicked off a project using React31, 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.

Helpful Background

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

React31 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 JSX4 — 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 Started5 guide.

Flux

Flux6 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.js7, 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 Flux8.

Introducing Lux.js

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.js9 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

Dmitri Voronianski created flux-comparison10, 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

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

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

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

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.js11 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

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 halon12, which understands how to consume our hypermedia resources using an extended version of HAL13 (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 good14 resources15 exist16 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.js17
Unidirectional data flow in lux.js. (View large version18)

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.19
Unidirectional data flow in lux.js: Update the UI. (View large version20)

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.js21
Unidirectional data flow in lux.js: Output of calling lux.utils.printActions(). (View large version22)

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.js23
Unidirectional data flow in lux.js: lux.utils.printStoreDepTree(actionName). (View large version24)

Lux + Ajax Examples

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

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

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

Actions, Stores And Remote Data I/O

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, revisited25”. 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 ]  )
        );
        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

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

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

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

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?

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

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

  1. 1 http://facebook.github.io/react/
  2. 2 http://facebook.github.io/react/blog/2014/05/06/flux.html
  3. 3 http://facebook.github.io/react/
  4. 4 http://facebook.github.io/react/docs/jsx-in-depth.html
  5. 5 http://facebook.github.io/react/docs/getting-started.html
  6. 6 https://facebook.github.io/flux/
  7. 7 https://github.com/LeanKit-Labs/lux.js
  8. 8 http://facebook.github.io/flux/docs/overview.html#content
  9. 9 https://github.com/LeanKit-Labs/lux.js
  10. 10 https://github.com/voronianski/flux-comparison
  11. 11 https://github.com/postaljs/postal.js
  12. 12 https://github.com/LeanKit-Labs/halon
  13. 13 https://tools.ietf.org/html/draft-kelly-json-hal-06
  14. 14 http://timelessrepo.com/haters-gonna-hateoas
  15. 15 http://martinfowler.com/articles/richardsonMaturityModel.html
  16. 16 http://phlyrestfully.readthedocs.org/en/latest/halprimer.html
  17. 17 http://www.smashingmagazine.com/wp-content/uploads/2015/05/01-luxdataflow1-opt.png
  18. 18 http://www.smashingmagazine.com/wp-content/uploads/2015/05/01-luxdataflow1-opt.png
  19. 19 http://www.smashingmagazine.com/wp-content/uploads/2015/05/02-luxdataflow2-opt.png
  20. 20 http://www.smashingmagazine.com/wp-content/uploads/2015/05/02-luxdataflow2-opt.png
  21. 21 http://www.smashingmagazine.com/wp-content/uploads/2015/05/03-luxPrintActions-opt.png
  22. 22 http://www.smashingmagazine.com/wp-content/uploads/2015/05/03-luxPrintActions-opt.png
  23. 23 http://www.smashingmagazine.com/wp-content/uploads/2015/05/04-luxPrintStoreDepTree-opt.png
  24. 24 http://www.smashingmagazine.com/wp-content/uploads/2015/05/04-luxPrintStoreDepTree-opt.png
  25. 25 http://www.code-experience.com/async-requests-with-react-js-and-flux-revisited/

The post Qualities Of Good Flux Implementations appeared first on Smashing Magazine.

Link: 

Qualities Of Good Flux Implementations