navigating the react.js ecosystem

The speed of innovation in JavaScript Land is so high, that some people even think it is counter-productive. A library can go from early-adopter toy, to state-of-art, to obsolescence in the course of a few months. Being able to identify a tool that is going to stay relevant for at least another year is becoming an art itself.

When React.js was released two years ago, I was just learning Angular, and I quickly dismissed React as some obscure yet-another-templating-library. During those two years, Angular really gained a foothold among JavaScript developers, and almost became synonymous with modern JS development. I even started seeing Angular in very conservative corporate environments, and I took it’s bright future for granted.

But suddenly, a strange thing happened. It seems Angular became a victim of the Osborne effect, or “death by pre-announcement”. The team announced that, first, Angular 2 will be completely different, without a clear migration path from Angular 1, and, second, that Angular 2 won’t be available for another year or so. What does that tell someone who want’s to start a new web project? Do you want to write your new project in a framework that is going to be made obsolete by a new version release?

This anxiety among developers played into the hands of React, which was seeking to establish itself in the community. But react always marketed itself as the “V” in “MVC.” This caused some amount of frustration among web developers, who are used to working with complete frameworks. How do I fill in the missing pieces? Should I write my own? Should I just use an existing library? If so, which one?

Sure enough, Facebook (creators of React.js) had one more ace in the hole: The Flux workflow, which promised to fill in the missing “M” and “C” functions. To make things even more interesting, Facebook stated that Flux is a “pattern,” not a framework, and their implementation of Flux is just one example of the pattern. True to their word, their implementation was really simplistic, and involved writing a lot of verbose, repetitive boilerplate to get things going.

The open source community came to the rescue, and a year later, we have dozens of Flux libraries, and even some meta-projects aimed at comparing them. This is a good thing; instead of releasing some ready-made corporate framework, Facebook has managed to stir interest in the community, and encouraged people to come up with their own solutions.

There’s one interesting side-effect to this approach: when you have to combine a lot of different libraries to get your complete framework, you are effectively escaping the vendor lock-in, and the innovations that emerge during your own framework construction can be readily reused elsewhere.

That’s why the new stuff around React is so interesting; most of it can be readily reused in other JavaScript environments. Even if you don’t plan on using React, taking a look at its ecosystem is inspiring. You may want to simplify your build system using the powerful, yet comparatively easy to configure, module bundler Webpack, or start writing ECMAScript 6 and even ECMAScript 7 today with the Babel compiler.

In this article, I’ll go through some of the interesting features and libraries that are available. So, let’s explore the React ecosystem!

React Explorer Man

Build System

The build system is arguably the first thing you should care about when creating a new web application. The build system is not only a tool for running scripts, but in the JavaScript world, it usually shapes the general structure of your application. The most important tasks a build system must cover are as follows:

  • Managing external and internal dependencies
  • Running compilers and preprocessors
  • Optimizing assets for production
  • Running the development web server, file watcher, and browser reloader

In recent years, the Yeoman workflow with Bower and Grunt were presented as the holy trinity of modern frontend development, solving the problems of boilerplate generation, package management, and common task running respectively, with the more progressive folk switching from Grunt to Gulp recently.

In the React environment, you can safely forget about these. Not that you couldn’t use them, but chances are you can just get away with using Webpack and good old NPM. How is that possible? Webpack is a module bundler, which implements CommonJS module syntax, common in the Node.js world, in the browser as well. It actually makes things simpler since you don’t need to learn yet another package manager for front end; you just use NPM and share dependencies between server and front end. You also don’t need to deal with the problem of loading the JS files in the correct order because it’s inferred from dependency imports specified in each file, and the whole swarm is correctly concatenated to one loadable script.

Webpack Logo Webpack

To make thing even more appealing, Webpack, unlike its older cousin Browserify, can handle other asset types as well. For example, with loaders, you can transform any asset file into a JavaScript function that either inlines, or loads, the referenced file. So, forget about manually preprocessing and referencing assets from HTML. Just require your CSS/SASS/LESS files from JavaScript, and Webpack takes care of the rest with a simple config file. Webpack also includes a development web server, and a file watcher. Plus, you can use the "scripts" key in package.json to define shell one-liners:

{
  "name": "react-example-filmdb",
  "version": "0.0.1",
  "description": "Isomorphic React + Flux film database example",
  "main": "server/index.js",
  "scripts": {
    "build": "./node_modules/.bin/webpack --progress --stats --config ./webpack/prod.config.js",
    "dev": "node --harmony ./webpack/dev-server.js",
    "prod": "NODE_ENV=production node server/index.js",
    "test": "./node_modules/.bin/karma start --single-run",
    "postinstall": "npm run build"
  }
  ...
}

And that’s about all you need to replace Gulp and Bower. Of course, you can still use Yeoman for generating application boilerplate. Don’t get discouraged when there’s no Yeoman generator for the stuff you want (the most cutting edge libraries often don’t have one). You can still just clone some boilerplate from GitHub, and hack away.

ECMAScript of Tomorrow, Today

The pace of JavaScript language development has substantially increased in recent years, and after a period of removing quirks and stabilizing the language, we now see powerful new features coming in. The ECMAScript 6 (ES6) specification draft has been finalized, and even though it has not been made official yet, it is already finding widespread adoption. Work on ECMAScript 7 (ES7) is in progress, but many of its features are already being adopted by the more cutting-edge libraries.

ECMAScript 7 Logo ECMAScript 7

How is this possible? Maybe you think you can’t take advantage of these shiny new JavaScript features until they are supported in Internet Explorer, but think again. ES transpilers have already become so ubiquitous that we can even do without proper browser support. The best ES transpiler available right now is Babel: it will take your newest ES6+ code, and transform it to vanilla ES5, so, you can use any new ES feature as soon as it is invented (and implemented in Babel, which usually happens quite quickly).

Babel Logo Babel

The newest JavaScript features are useful across all front end frameworks, and React has recently been updated to work nicely with the ES6 and ES7 specifications. These new features should eliminate a lot of headaches when developing with React. Let’s take a look at some of the most useful additions, and how they can benefit a React project. Later, we’ll see how to use some useful tools and libraries with React while harnessing this improved syntax.

ES6 classes

Object-oriented programming is a powerful and widely-adopted paradigm, but JavaScript’s take on it is a bit exotic. Most of the front end frameworks, be it Backbone, Ember, Angular, or React, have thus adopted their own proprietary ways of defining classes and creating objects. But with ES6, we now have traditional classes in JavaScript, and it simply makes sense to use them instead of writing our own implementation. So, instead of:

React.createClass({
  displayName: 'HelloMessage',
  render() {
    return <div>Hello {this.props.name}</div>;
  }
})

we can write:

class HelloMessage extends React.Component {
  render() {
    return <div>Hello {this.props.name}</div>;
  }
}

For a more elaborate example, consider this code, using the old syntax:

React.createClass({
  displayName: 'Counter',
  getDefaultProps: function(){
    return {initialCount: 0};
  },
  getInitialState: function() {
    return {count: this.props.initialCount} 
  },
  propTypes: {initialCount: React.PropTypes.number},
  tick() {
    this.setState({count: this.state.count + 1});
  },
  render() {
    return (
      <div onClick={this.tick}>
        Clicks: {this.state.count}
      </div>
    );
  }
});

And compare to the ES6 version:

class Counter extends React.Component {
  static propTypes = {initialCount: React.PropTypes.number};
  static defaultProps = {initialCount: 0};

  constructor(props) {
    super(props);
    this.state = {count: props.initialCount};
  }

  state = {count: this.props.initialCount};
  tick() {
    this.setState({count: this.state.count + 1});
  }

  render() {
    return (
      <div onClick={this.tick.bind(this)}>
        Clicks: {this.state.count}
      </div>
    );
  }
}

Here, the React lifecycle methods getDefaultProps and getInitialState are no longer necessary. getDefaultProps becomes the static class variable defaultProps, and initial state is just defined in the constructor. The only drawback is, methods are no longer autobound, so you have to use bind when calling handlers from JSX.

Decorators

Decorators are a useful feature from ES7. They allow you to augment the behavior of a function or class by wrapping it inside another function. For example, let’s assume that you want to have the same change handler on some of your components, but you don’t want to commit to the inheritance antipattern. You can use a class decorator instead. Let’s define the decorator as follows:

addChangeHandler: function(target) {
  target.prototype.changeHandler = function(key, attr, event) {
    var state = {};
    state[key] = this.state[key] || {};
    state[key][attr] = event.currentTarget.value;
    this.setState(state);
  };
  return target;
}

The important thing here is that the function addChangeHandler adds the changeHandler function to the prototype of the target class.

To apply the decorator, we could write:

MyClass = changeHandler(MyClass)

or more elegantly, with ES7 syntax:

@addChangeHandler
class MyClass {
  ...
}

As for content of the changeHandler function itself, with React’s absence of two-way data binding, working with inputs in React can be tedious. The changeHandler function tries to make it easier. The first parameter specifies a key on the state object, which will serve as a data object for the input. The second parameter is the attribute, to which the value from the input field will be saved. Those two parameters are set from JSX using the bind keyword.

@addChangeHandler
class LoginInput extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      login: {}
    };
  }
  render() {
    return (
      <input
        type='text'
        value={this.state.login.username}
        onChange={this.changeHandler.bind(this, 'login', 'username')} />
      <input
        type='password'
        value={this.state.login.password}
        onChange={this.changeHandler.bind(this, 'login', 'password')} />
    )
  }
}

When the user changes the username field, its value is saved to this.state.login.username, without the need of defining more custom handlers.

Arrow Functions

JavaScript’s dynamic this context has been a constant pain to developers because, somewhat unintuitively, the this context of a nested function is reset to global, even inside a class. To fix this, it’s usually necessary to save this to some outer scope variable (usually _this) and use it in inner functions:

class DirectorsStore {
  onFetch(directors) {
    var _this = this;
    this.directorsHash = {};
    directors.forEach(function(x){
      _this.directorsHash[x._id] = x;
    })
  }
}

With the new ES6 syntax, the function(x){ can be rewritten as (x) => {. This “arrow” method definition not only correctly binds this to the outer scope, but is also considerably shorter, which definitely counts when writing a lot of asynchronous code.

onFetch(directors) {
  this.directorsHash = {};
  directors.forEach((x) => {
    this.directorsHash[x._id] = x;
  })
}

Destructuring Assignments

Destructuring assignments, introduced in ES6, allow you to have a compound object on the left side of an assignment:

var o = {p: 42, q: true};
var {p, q} = o;

console.log(p); // 42
console.log(q); // true 

This is nice, but how does it actually help us in React? Consider the following example:

function makeRequest(url, method, params) {
  var config = {
    url: url,
    method: method,
    params: params
  };
  ...
}

With destructuring, you can save a few keystrokes. The keys literal {url, method, params} is automatically assigned values from scope with same names as the keys. This idiom is used quite often, and eliminating repetition makes the code less error-prone.

function makeRequest(url, method, params) {
  var config = {url, method, params};
  ...
}

Destructuring can also help you load just a subset of a module:

const {clone, assign} = require('lodash');
function output(data, optional) {
  var payload = clone(data);
  assign(payload, optional);
}

Arguments: Default, Rest, and Spread

Function arguments are more powerful in ES6. Finally, you can set the default argument:

function http(endpoint, method='GET') {
  console.log(method)
  ...
}

http('/api') // GET

Tired of messing with the unwieldy arguments object? With the new specification, you can get the rest of the arguments as an array:

function networkAction(context, method, ...rest) {
  // rest is an array
  return method.apply(context, rest);
}

And if you don’t like calling apply(), you can just spread an array into function arguments:

myArguments = ['foo', 'bar', 123];
myFunction(...myArguments);

Generators and Async Functions

ES6 introduced JavaScript generators. A generator is basically a JavaScript function whose execution can be paused and then resumed later, remembering its state. Each time the yield keyword is encountered, execution is paused, and the yield argument is passed back to the calling object:

function* sequence(from, to) {
  console.log('Ready!');
  while(from <= to) {
    yield from++;
  }
}

Here’s an example of this generator in action:

> var cursor = sequence(1,3)
Ready!
> cursor.next()
{ value: 1, done: false }
> cursor.next()
{ value: 2, done: false }
> cursor.next()
{ value: 3, done: false }
> cursor.next()
{ value: undefined, done: true }

When we call the generator function, it executes until the first yield, and then stops. After we call next(), it returns the first value, and resumes execution. Each yield returns another value, but after the third call, the generator function terminates, and each subsequent call to next() will return { value: undefined, done: true }.

Of course, the point of generators is not to create elaborate numerical sequences. The exciting part is their ability to stop and resume function execution, which can be used to control asynchronous program flow and finally get rid of those pesky callback functions.

To demonstrate this idea, we first need an asynchronous function. Usually, we’d have some I/O operation, but for simplicity, let’s just use setTimeout and return a promise. (Note that ES6 also introduced native promises to JavaScript.)

function asyncDouble(x) {
  var deferred = Promise.defer();
  setTimeout(function(){
    deferred.resolve(x*2);
  }, 1000);
  return deferred.promise;
}

Next, we need a consumer function:

function consumer(generator){
  var cursor = generator();
  var value;
  function loop() {
    var data = cursor.next(value);
    if (data.done) {
      return;
    } else {
      data.value.then(x => {
        value = x;
        loop();
      })
    }
  }
  loop();
}

This function takes any generator as an argument, and keeps calling next() on it as long as there are values to yield. In this case, the yielded values are promises, and so it is necessary to wait for the promises to resolve, and use recursion with loop() to achieve looping across nested functions.

The return value is resolved in the then() handler, and passed to value, which is defined in the outer scope, and which will get passed into the next(value) call. This call makes the value a result of the corresponding yield expression. This means that we are now able to write asynchronously without any callbacks at all:

function* myGenerator(){
  const data1 = yield asyncDouble(1);
  console.log(`Double 1 = ${data1}`);
  const data2 = yield asyncDouble(2);
  console.log(`Double 2 = ${data2}`);
  const data3 = yield asyncDouble(3);
  console.log(`Double 3 = ${data3}`);
}

consumer(myGenerator);

The generator myGenerator will be paused on each yield, waiting for consumer to deliver the resolved promise. And indeed, we’ll see the computed numbers appear in the console in one-second intervals.

Double 1 = 2
Double 2 = 4
Double 3 = 6

This demonstrates the basic concept, however, I don’t recommend that you use this code in production. Instead, choose a well-tested library such as co. This will allow you to easily write async code with yields, including error handling:

co(function *(){
  var a = yield Promise.resolve(1);
  console.log(a);
  var b = yield Promise.resolve(2);
  console.log(b);
  var c = yield Promise.resolve(3);
  console.log(c);
}).catch(function(err){
  console.error(err.stack);  
});

So, this example shows how to write asynchronous code without callbacks using ES6 generators. ES7 takes this approach one step further by introducing the async and await keywords, and removing the need for a generator library altogether. With this capability, the previous example would look like this:

async function (){
  try {
    var a = await Promise.resolve(1);
    console.log(a);
    var b = await Promise.resolve(2);
    console.log(b);
    var c = await Promise.resolve(3);
    console.log(c);
  } catch (err) {
    console.error(err.stack);  
  }
};

In my opinion, this takes the pain out of working with asynchronous code in JavaScript. Not only in React, but everywhere else, as well.

Generators are not only more concise and straightforward, but also allow us to use techniques that would be very hard to implement with callbacks. A prominent example of generator goodness is the koa middleware library for Node.js. It aims to replace Express, and, towards that goal, it comes with one killer feature: The middleware chain flows not only downstream (with client request), but also upstream, allowing further modification to the server’s response. Consider the following koa server example:

// Response time logger middleware
app.use(function *(next){
  // Downstream
  var start = new Date;
  yield next;
  // Upstream
  this.body += ' World';
  var ms = new Date - start;
  console.log('%s %s - %s', this.method, this.url, ms);
});

// Response handler
app.use(function *(){
  this.body = 'Hello';
});

app.listen(3000);  

Koa Logo Koa

The response middleware yields downstream into the response handler, which sets the response body, and in the upstream flow (after the yield expression), further modification of this.body is allowed, as well as other functions like time logging, which is possible because the upstream and downstream shares the same function context. This is much more powerful than Express, in which an attempt to accomplish the same thing would end like this:

var start;
// Downstream middleware
app.use(function(req, res, next) {
  start = new Date;
  next();
  // Already returned, cannot continue here
});

// Response
app.use(function (req, res, next){
  res.send('Hello World')
  next();
});

// Upstream middleware
app.use(function(req, res, next) {
  // res already sent, cannot modify
  var ms = new Date - start;
  console.log('%s %s - %s', this.method, this.url, ms);
  next();
});

app.listen(3000);  

You can probably already spot what’s wrong here; using a “global” start variable will result in a race condition, returning nonsense with concurrent requests. The solution is some non-obvious workaround, and you can forget about modifying the response in the upstream flow.

Also, when using koa, you’ll get the generator asynchronous workflow for free:

app.use(function *(){
  try {
    const part1 = yield fs.readFile(this.request.query.file1, 'utf8');
    const part2 = yield fs.readFile(this.request.query.file2, 'utf8');
    this.body = part1 + part2;
  } catch (err) {
    this.status = 404
    this.body = err;
  }
});

app.listen(3000);

You can imagine the promises and callbacks involved in re-creating this small example in Express.

Node.js Logo

How does all of this Node.js talk relate to React? Well, Node is the first choice when considering a suitable back end for React. Since Node is written in JavaScript as well, it supports code sharing between back end and front end, allowing us to build isomorphic React web applications. But, more about this later.

Flux Library

React is great at creating composable view components, but we need some way to manage data and state across the whole application. It has been almost universally agreed that React is best complemented by the Flux application architecture. If you are completely new to Flux, I recommend a quick refresh.

Flux Logo Flux

What has not been so universally agreed is which of the many Flux implementations to choose. Facebook Flux would be the obvious choice, but for most people it’s too verbose. Alternative implementations focus mostly on reducing the amount of required boilerplate with a convention-over-configuration approach, and also with some convenience functions for higher-order components, server-side rendering, and so on. Some of the top contenders, with various popularity metrics, can be seen here. I’ve looked into Alt, Reflux, Flummox, Fluxxor, and Marty.js.

My way of choosing the right library is in no way objective, but it might help anyway. Fluxxor was one of this first libraries I checked out, but now it looks a bit stale. Marty.js is interesting, and has a lot of features, but still involves a lot of boilerplate, and some of the functions seem superfluous. Reflux looks great and has some traction, but feels a bit hard for beginners, and also lacks proper documentation. Flummox and Alt are very similar, but Alt seems to have even less boilerplate, very active development, up-to-date documentation and a helpful Slack community.Therefore, I chose Alt.

Alt Flux

Alt Flux Logo Alt Flux

With Alt, the Flux workflow becomes much simpler without losing any of it’s power. Facebook’s Flux documentation says a lot about the dispatcher, but we are free to ignore that because, in Alt, the dispatcher is implicitly wired to actions by convention, and usually doesn’t require any custom code. This leaves us with just stores, actions, and components. These three layers may be used in such a way that they map nicely into the MVC thought model: Stores are Models, actions are Controllers, and components are Views. The main difference is the unidirectional data flow central to the Flux pattern, which means, that controllers (actions) cannot directly modify views (components), but, instead, can only trigger model (store) modifications, to which views are passively bound. This was already a best practice for some enlightened Angular developers.

Flux vs. Alt Workflows

The workflow is as follows:

  1. Components initiate actions.
  2. Stores listen to actions and update data.
  3. Components are bound to stores, and rerender when data are updated.

Actions

When using the Alt Flux library, actions generally come in two flavors: automatic and manual. Automatic actions are created using the generateActions function, and they go directly to the dispatcher. Manual methods are defined as methods of your action classes, and they can go to the dispatcher with an additional payload. The most common use case of automatic actions is to notify stores about some event in the application. Manual actions are, among other things, the preffered way of dealing with server interactions.

So the REST API calls belong to actions. The complete workflow is as follows:

  1. Component triggers an action.
  2. The action creator runs an asynchronous server request, and the result goes to the dispatcher as a payload.
  3. The store listens to the action, the corresponding action handler receives the result as an argument, and the store updates its state accordingly.

For AJAX requests, we can use the axios library, which, among other things, deals with JSON data and headers seamlessly. Instead of promises or callbacks, we can use the ES7 async/await pattern. If the POST response status is not 2XX, an error is thrown, and we dispatch either returned data, or received error.

Let’s look at a login page for a simple example of the Alt workflow. The logout action does not need to do anything special, only notify the store, so we can generate it automatically. The login action is manual, and expects login data as a parameter to the action creator. After we get a response from server, we either dispatch success data, or, if an error is thrown, we dispatch the error received.

class LoginActions {
  constructor() {
    // Automatic action
    this.generateActions('logout');
  }

  // Manual action
  async login(data) {
    try {
      const response = await axios.post('/auth/login', data);
      this.dispatch({ok: true, user: response.data});
    } catch (err) {
      console.error(err);
      this.dispatch({ok: false, error: err.data});
    }
  }
}

module.exports = (alt.createActions(LoginActions));

Stores

The Flux store serves two purposes: It has action handlers, and carries state. Let’s continue our login page example to see how this works.

Let’s create LoginStore, with two state attributes: user, for the current logged-in user, and error, for the current login-related error. In the spirit of reducing boilerplate, Alt allows us to bind to all actions from one class with a single function bindActions.

class LoginStore {
  constructor() {
    this.bindActions(LoginActions);
    this.user = null;
    this.error = null;
  }
  ...

Handler names are defined by convention, prepending on to the corresponding action name. So the login action is handled by onLogin, and so forth. Note that the first letter of the action name will be capitalized in camelCase style. In our LoginStore, we have the following handlers, called by the corresponding actions:

  ...
  onLogin(data) {
    if (data.ok) {
      this.user = data.user;
      this.error = null;
      router.transitionTo('home');
    } else {
      this.user = null;
      this.error = data.error
    }
  }

  onLogout() {
    this.user = null;
    this.error = null;
  }
}

Components

The usual way of binding stores to components is to use some kind of React mixin. But since mixins are going out of fashion, there needs to be some other way. One of the new approaches is to use higher-order components. We take our component and put it inside a wrapper component, which will take care of listening to stores and calling re-render. Our component will receive the store’s state in props. This approach is also helpful to organize our code into smart and dumb components, which have become trendy lately. For Alt, the component wrapper is implemented by AltContainer:

export default class Login extends React.Component {
  render() {
    return (
      <AltContainer stores={{LoginStore: LoginStore}}>
        <LoginPage/>
      </AltContainer>
  )}
}

Our LoginPage component also uses the changeHandler decorator introduced earlier. Data from LoginStore is used to display errors in case of an unsuccessful login, and re-rendering is taken care of by AltContainer. Clicking on the login button executes the login action, completing the Alt flux workflow:

@changeHandler
export default class LoginPage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      loginForm: {}
    };
  }
  login() {
    LoginActions.login(this.state.loginForm)
  }
  render() {
    return (
      <Alert>{{this.props.LoginStore.error}}</Alert>
      <Input
        label='Username'
        type='text'
        value={this.state.login.username}
        onChange={this.changeHandler.bind(this, 'loginForm', 'username')} />
      <Input
        label='Password'
        type='password'
        value={this.state.login.password}
        onChange={this.changeHandler.bind(this, 'loginForm', 'password')} />
      <Button onClick={this.login.bind(this)}>Login</Button>
  )}
}

Isomorphic Rendering

Isomorphic web applications are a hot topic these days because they solve some of the biggest chores of traditional single page applications. In those applications, markup is created dynamically by JavaScript in the browser. The result is that the content is not available to clients with JavaScript turned off, most notably, search engine web crawlers. This means your web page is not indexed and does not appear in search results. There are ways to work around this, but they are far from optimal. The isomorphic approach attempts to fix this problem by pre-rendering the requested URL of a single page application on the server. With Node.js, you have JavaScript on the server, meaning React can also run server-side. This shouldn’t be too hard, right?

One obstacle is that some Flux libraries, especially those that use singletons, have difficulties with server-side rendering. When you have singleton Flux stores and multiple concurrent requests to your server, the data will get mixed up. Some libraries solve this by using Flux instances, but this comes with other drawbacks, particularly the need to pass those instances around in your code. Alt offers Flux instances too, but it has also solved the problem of server-side rendering with singletons; it flushes stores after each request, so that each concurrent request starts with a clean slate.

The core of the server-side rendering functionality is provided by React.renderToString. The whole React front end application is run on the server, as well. This way, we don’t need to wait for the client-side JavaScript to create the markup; it’s pre-built on the server for the accessed URL, and sent to the browser as HTML. When the client JavaScript runs, it picks up where the server has left off. To support this, we can use the Iso library, which is meant to be used with Alt.

First, we initialize Flux on the server using alt.bootstrap. It is possible to prefill the Flux stores with data for rendering. It is also necessary to decide which component to render for which URL, which is the functionality of the client side Router. We are using the singleton version of alt, so after each render, we need to alt.flush() the stores to have them clean for another request. Using the iso add-on, the state of Flux is serialized to the HTML markup, so that the client knows where to pick up:

// We use react-router to run the URL that is provided in routes.jsx
var getHandler = function(routes, url) {
  var deferred = Promise.defer();
  Router.run(routes, url, function (Handler) {
    deferred.resolve(Handler);
  });
  return deferred.promise;
};

app.use(function *(next) {
  yield next;
  // We seed our stores with data
  alt.bootstrap(JSON.stringify(this.locals.data || {}));
  var iso = new Iso();
  const handler = yield getHandler(reactRoutes, this.request.url);
  const node = React.renderToString(React.createElement(handler));
  iso.add(node, alt.flush());
  this.render('layout', {html: iso.render()});
});

On the client side, we pick up the server state, and bootstrap alt with the data. Then we run Router and React.render on the target container, which will update the server-generated markup as necessary.

Iso.bootstrap(function (state, _, container) {
  // Bootstrap the state from the server
  alt.bootstrap(state)
  Router.run(routes, Router.HistoryLocation, function (Handler, req) {
    let node = React.createElement(Handler)
    React.render(node, container)
  })
})

Lovely!

Useful Front-End Libraries

A guide to the React ecosystem wouldn’t be complete without mentioning a few front-end libraries that play especially well with React. These libraries tackle the most common tasks found in almost every web application: CSS layouts and containers, styled forms and buttons, validations, date picking, and so on. There’s no point in reinventing the wheel when those problems have been solved already.

React-Bootstrap

React-Bootstrap Logo

Twitter’s Bootstrap framework has become commonplace since it is of immense help to every web developer who does not want to spend a ton of time working in CSS. In the prototyping phase especially, Bootstrap is indispensable. To leverage the power of bootstrap in a React application, it’s good to use it with React-Bootstrap, which comes with nice React syntax and re-implements Bootstrap’s jQuery plugins using native React components. The resulting code is terse and easy to understand:

<Navbar brand='React-Bootstrap'>
  <Nav>
    <NavItem eventKey={1} href='#'>Link</NavItem>
    <NavItem eventKey={2} href='#'>Link</NavItem>
    <DropdownButton eventKey={3} title='Dropdown'>
      <MenuItem eventKey='1'>Action</MenuItem>
      <MenuItem eventKey='2'>Another action</MenuItem>
      <MenuItem eventKey='3'>Something else here</MenuItem>
      <MenuItem divider />
      <MenuItem eventKey='4'>Separated link</MenuItem>
    </DropdownButton>
  </Nav>
</Navbar>

Personally, I cannot escape the feeling that this is what HTML should always have been like.

If you want to use Bootstrap source with Webpack, consider using less-loader or bootstrap-sass-loader, depending on the preprocessor you prefer. It will allow you to easily customize which Bootstrap components to include, and also allow the usage of LESS or SASS global variables in your CSS code.

React Router

React Router Logo

React Router has become the de-facto standard for routing in React. It allows nested routing, support for redirections, plays nicely with isomorphic rendering, and has a simple JSX-based syntax:

<Router history={new BrowserHistory}>
  <Route path="/" component={App}>
    <Route path="about" name="about" component={About}/>
    <Route path="users" name="users"  component={Users} indexComponent={RecentUsers}>
      <Route path="/user/:userId" name="user" component={User}/>
    </Route>
    <Route path="*" component={NoMatch}/>
  </Route>
</Router>

React Router also provides a Link component that you can use for navigation in your application, specifying only the route name:

<nav>
  <Link to="about">About</Link>
  <Link to="users">Users</Link>
</nav>

There is even a library for integration with React-Bootstrap, so if you are using Bootstrap’s components and don’t feel like setting the active class on them manually all the time, you can use react-router-bootstrap and write code like this:

<Nav>
  <NavItemLink to="about">About</NavItemLink>
  <NavItemLink to="users">Users</NavItemLink>
</Nav>

No additional setup is necessary. Active links will take care of themselves.

Formsy-React

Working with forms can be tedious, so let’s get some help from the formsy-react library, which will help us manage validations and data models. The Formsy-React library, strangely enough, does not include the actual form inputs because users are encouraged to write their own (which is great). But if you are content with the common ones, just use formsy-react-components. Bootstrap classes are included:

import Formsy from 'formsy-react';
import {Input} from 'formsy-react-components';
export default class FormsyForm extends React.Component {
  enableButton() {
    this.setState({canSubmit: true});
  }
  disableButton() {
    this.setState({canSubmit: true});
  }
  submit(model) {
    FormActions.saveEmail(model.email);
  }
  render() {
    return (
      <Formsy.Form onValidSubmit={this.submit} onValid={this.enableButton} onInvalid={this.disableButton}>
        <Input 
          name="email" 
          validations="isEmail" 
          validationError="This is not a valid email" 
          required/>
        <button type="submit" disabled={!this.state.canSubmit}>Submit</button>
      </Formsy.Form>
  )}
}

Calendar and Typeahead

Calendar and typeahead are icing on the cake of every UI toolkit. Sadly, these two components were removed from Bootstrap 3, probably because they are too specialized for a general purpose CSS framework. Luckily, I’ve been able to find worthy replacements in react-pikaday and react-select. I’ve tested more than 10 libraries, and these two came out as the best. They are dead easy to use, as well:

import Pikaday from 'react-pikaday';
import Select from 'react-select';

export default class CalendarAndTypeahead extends React.Component {
  constructor(props){
    super(props);
    this.options = [
      { value: 'one', label: 'One' },
      { value: 'two', label: 'Two' }
    ];
  }
  dateChange(date) {
    this.setState({date: date});
  },
  selectChange(selected) {
    this.setState({selected: selected});
  },
  render() {
    return (
      <Pikaday 
        value={this.state.date} 
        onChange={this.dateChange} />
      <Select
        name="form-field-name"
        value={this.state.selected}
        options={this.options}
        onChange={selectChange} />
  )}
}
When it comes to React, it's a jungle out there! Here's a map to help you find your way.

Conclusion - React.JS

In this article I’ve presented libraries and techniques that I consider some of the most productive in current web development. Some of them are React-specific, but due to React’s open nature, many of them are usable in other environments as well. Technological progress is sometimes hindered by fear of the newest stuff, so I hope this article will help to dissipate doubts concerning React, Flux and the newest features in ECMAScript.

React Ecosystem

If you are interested, you can take a look at my example application built with these technologies. The source code is available on GitHub.

Thanks for reading!

About the author

Tomas Holas, Czech Republic
member since January 13, 2015
Tomas started as a Ruby on Rails enthusiast, but in 2010 he turned to JavaScript and never looked back. JavaScript has a really productive ecosystem, which is easy to hack on, and offers libraries for everything imaginable. Currently, he prefers to work with Angular, React, and NodeJS. Why hire Tomas? He strictly adheres to the KISS approach, prioritizing productivity over programmatic parlor tricks where a library is sufficient. [click to continue...]
Hiring? Meet the Top 10 Freelance React.js Developers for Hire in July 2016

Comments

Konstantin Tarkus
Why don't you use async/await in your express.js example? It could look something like this: <pre><code>server.get('/path', async (req, res, next) => { const start = new Date(); const data = await fs.readFile('/some-file.txt'); await next(); console.log('Response time (ms):', new Date() - start); });</code></pre>
Konstantin Tarkus
<strong><a href="https://github.com/kriasoft/react-starter-kit">React Starter Kit</a></strong> <- Yet another project which may help with React.js development.
Lucas Souza
Great article!
Antonio Chavez
Amazing article about React ecosystem. I'm really interested on the application setup from the server side, I've been exploring your code and from what I see there's a lot of framework conventions for that, which makes it a little bit hard to understand. Kudos for the great work!
Tomáš Holas
True, that would work. I think at time of writing, I had only ES6 on server. Funny how this stuff obsoletes so quickly. Still, it does not resolve the missing upstream issue.
Tomáš Holas
I always liked convention over configuration. If you have specific questions, I'm ready to answer them here :)
Filip Petkovski
Thanks for the great article Tomáš! It's obvious that you've put a lot of effort in it.
Luboš Volkov
It's all the time pleasure to see great Czech people joining Toptal :) good post!
byofuel
Don't forget Pellet, the isomorphic React framework used by Vevo, which has the largest scaled React site outside of Facebook. https://github.com/Rebelizer/pellet
KenPowersCS
For entries in "scripts" in your `package.json` file you don't need full paths to executables installed by your dependencies. This: <pre><code> "build": "./node_modules/.bin/webpack --progress --stats --config ./webpack/prod.config.js", </code></pre> Can be shortened to: <pre><code> "build": "webpack --progress --stats --config ./webpack/prod.config.js", </code></pre>
KenPowersCS
Rather than use <pre><code>.bind</code></pre> in params I'd suggest using arrow functions: <pre><code>onChange={this.changeHandler.bind(this, 'login', 'username')}</pre></code> Is basically the same as: <pre><code>onChange={() => this.changeHandler('login', 'username')}</pre></code> Or, if you want the event object as well: <pre><code>onChange={e => this.changeHandler(e, 'login', 'username')}</pre></code>
Tomáš Holas
Great! I was already thinking about how to integrate Jade with React. It's good to see somebody did it already.
Nikola Brežnjak
Hey Tomas, great overview. However, I'm wondering, since I see that you still have in your bio that you work with Angular. How are you thoughts about Angular 2 now that's it's quite near going to production? Migrating back to it from React, or are you staying put?
Rifat Nabi
Great article. A small correction. You use `static` is ES6/2015 example but `static` is in ES7/2016 AFAIK. Thanks again for such an informative article :)
akoskm
Great introduction about the React.js ecosystem! I would like to know why the class keyword is so overhyped? JavaScript can simulate the class system without the class keyword, but why would you do that when you have prototypal inheritance?
Alexander Pustovalov
There is another tool for prototyping real React components: React UI Builder (https://www.npmjs.com/package/react-ui-builder)
Filip Petkovski
Partly because people still haven't learned JavaScript properly. Many people who are front-end developers have come from the Java/.Net/PHP world where functions were not really first-class citizens up until recently.
Luca Colonnello
Great article Tomas! I posted a similar article to Medium, about Past and Present of Web Technologies. This is the detailed explaination of what might be the future of Web App development. So I think I'll link this article in mine, so it could be more comprehensive.
SteveALee
Did you look at Yahoo Fluxable? It looks interesting given your requirements.
soundyogi
React ecosystem? This is a de-facto js article. Very nice. thanks!
Safi
<i>"Alt offers Flux instances too, but it has also solved the problem of server-side rendering with singletons; it flushes stores <b>after</b> each request, so that each concurrent request starts with a clean slate."</i> <i>"We are using the singleton version of alt, so <b>after</b> each render, we need to alt.flush() the stores to have them clean for another request."</i> Words "concurrency" and "after" do not mix well together. :) Does this mean actually that there is no concurrency and requests are serialized? If yes, isn't serializing requests a huge bottleneck? Great article btw, thanks!
DanScanlon
I strongly suggest looking into Redux. With stateless reducers in place of stores, and its use of Provider v.s. a singleton, it's one of the cleanest Flux implementations out right now.
Fred Daoud
Superb article, Tomáš! A vast amount of interesting material and a great read. Thank you for this write-up! I wanted to share an npm fact that (apparently) many people have not noticed in their documentation. When you write scripts, npm automatically adds paths to binaries from the installed modules. Thus, you can simplify your scripts like this: "build": "webpack --progress --stats --config ./webpack/prod.config.js", "test": "karma start --single-run", You do NOT have to install webpack and karma-cli with '-g' for this to work. I find this very convenient! Cheers, Fred
Patrick
Very helpful article. But I still have a question. When looking at the example code, it seems that DOM manipulation is part of components (e.g. modal show or similar). Is this supposed to be best practice or do you decide that based on the usecase? For example, I have a jQuery function which is being used by several components. I could now add that call to a click handler within each component ... or I could add the function call to exactly one store. To me, the latter seems more maintainable, but maybe I'm missing something.
David Krmpotic
I concur.. it's almost the same feeling when you go to redux from other flux frameworks than it is from jQuery to React way of doing things :)
David Krmpotic
https://github.com/gaearon/redux and a great recent video from the author of redux Dan Abramov: https://www.youtube.com/watch?v=xsSnOQynTHs
Tomáš Holas
Words "concurrency" and "after" do not mix well together That is so true. So to clarify this, you must not make any asynchronous action between bootstrap and flush. In evented-style JavaScript concurency, I believe this is safe. More in Alt documentation: http://alt.js.org/docs/flush/
Tomáš Holas
I started to really like React, and I'm definitelly not going back to Angular 1. Also, it's going to take at least another year before Angular 2 jobs will start appearing, if ever. So for now, I stay with React.
Tomáš Holas
I used full paths to be safe. I had some conflicts with globally installed modules.
Nikola Brežnjak
Ok, well, I guess it's time to properly dive in and (Re)act then :)
Tomáš Holas
I think that DOM manipulations should be best avoided unless absolutely necessary, for example when wrapping thirdparty components in React. Then you should do it in componentDidMount. But in no way I'd put jQuery code inside a store. For reuse, it belongs to a module, and you can get it with require/import.
Xavier Carpentier
Thx a lot ! Very good post ! I did inspect the result : https://react-example-filmdb.herokuapp.com. And I am impressed that isomorphic work, but I didn't saw how... I saw the server generation result from HTML sources but it's transparent. Is Isomorphic architecture using Ajax to reload HTML ? (no sense) In network tab I see only the JSON and no location changing page, why ? Do you have some infos for me ? plz Xavier
Rifat Nabi
getDefaultProps becomes the static class variable propTypes Here it should be `defaultProps` instead of `propTypes`
Nick McCrea
Great catch Rifat. Thank you! This has been corrected. -Editor
Tomáš Holas
Isomorphic architecture does load HTML only on the first request. Subsequent pages are generated on the client from React application and only need REST API calls.
Chaïmâe
You know what ? You just made some decisions really easy and thank you :)
mastazi
@tomholas:disqus as of January 2016, a significant part of the community shifted to Redux, which unfortunately is not mentioned in the article. Given that your article has a huge visibility on Google and it is often cited as a great guide to the React ecosystem, I wish you could insert an "Update" note at least citing the fact that Redux exists and that it has significant following.
auvipy
cool!! but you could consider reduxjs now for flux!!! its best till now :D
Konstantin Tsabolov
Great introduction to React world! Thank you. I have just one remark related to Destructuring assignment. Your example with <pre><code class="javascript">config = { url, method, params }</code></pre> is not a demonstration of destructuring assignment, but is a demonstration of <b>Shorthand property names</b> (as described at https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Object_initializer#Property_definitions).
Thắng Phạm
Great example. So amazing! Thank you so much :D
Thắng Phạm
Hi guys, I'm trying to run this command line: npm install but it has some error that some package can't be installed. Any idea to resolve it? Thanks a lot!
Maurits van Mastrigt
Very well written and in depth article. Thank you! PS. I believe this should be changed: To apply the decorator, we could write: MyClass = changeHandler(MyClass) To: addChangeHandler(MyClass)
comments powered by Disqus
Subscribe
The #1 Blog for Engineers
Get the latest content first.
No spam. Just great engineering and design posts.
The #1 Blog for Engineers
Get the latest content first.
Thank you for subscribing!
You can edit your subscription preferences here.
Trending articles
Relevant technologies
About the author
Tomas Holas
JavaScript Developer
Tomas started as a Ruby on Rails enthusiast, but in 2010 he turned to JavaScript and never looked back. JavaScript has a really productive ecosystem, which is easy to hack on, and offers libraries for everything imaginable. Currently, he prefers to work with Angular, React, and NodeJS. Why hire Tomas? He strictly adheres to the KISS approach, prioritizing productivity over programmatic parlor tricks where a library is sufficient.