React, Flux, localForage and Saving Data

Remember my vague promise to write an awesome app? The one where I would do something more than just a basic task list like todomvc? Well, I’m progressing. Right now, my HoneyDo application has the ability to edit tasks through a bunch of React components and it loads and saves data from the disk. I haven’t quite got to the point of adding tasks yet – that’s tomorrows project.

Today I want to talk about saving and loading data. I thought that it would be a little bit more efficient as I worked towards a cloud service if I persisted the data I was storing in memory to disk. I want to be able to load up the web page and then see the same tasks as before, so it makes sense to store them locally. However, I’m expecting latency in the process, so I don’t want to repeatedly save for every single change. Changes happen for every single letter in the title, for example. Saving every change would produce a lot of latency. I do want to indicate whether the data has been saved or not, somewhere in the banner.

The Dirty Store

At its core, my flux/TaskStore.js handles an array of models/Task objects with a bunch of methods for CRUD operations. To facilitate the functionality required, I did the following:

  • Added a dirty field to the Task model that can be set and cleared.
  • Added a saving field to the TaskStore to indicate that saving is active.
  • Added code so that when the Task was changed, the dirty flag was set on the Task model.
  • Added an indicator of the dirty status to the TaskListItem.jsx component.

Basically, the tasks now have a dirty flag and the store has a saving indicator.

Loading Tasks

To store tasks persistently, I used the localForage module. This is a Mozilla module that abstracts the various methods of storing data persistently and provides a Promise-based API. It provides the same API as localStorage, but it has two improvements – firstly, it uses Promises so it’s asynchronous out of the box. Secondly, it can store arrays, objects, numbers and so on – localStorage likes strings only. The localForage API handles the serialization for you if needed.

Loading tasks becomes easy. This is taken from the flux/TaskStore.js file:

  loadTasks() {
    localforage.iterate((value, key, iterationNumber) => {
      this.tasks.push(Task.deserialize(value));
    });
    if (this.tasks.length == 0) {
      this.initializeTasks();
    }
    this.changeStore();
  }

The loadTasks() method is called in the constructor. If there is nothing there, then I call initializeTasks() which creates three tasks to show off the interface. Note that in the code that is checked in, I have an alternate path. This is done for backwards compatibility and you can generally ignore it.

Saving Tasks

Saving tasks is not as easy:

  saveTasks() {
    // Return immediately if the store is not dirty OR we are already saving
    if (!this.isDirty() || this.saving) {
      return;
    }

    // Set the dirty flag to false and the saving flag to true
    this.saving = true; this.changeStore();

    // Loop through the tasks that are dirty and store them
    this.tasks.filter(t => t.dirty).forEach(t => {
      localforage.setItem(t.id, t.serialize());
      t.dirty = false;
    });

    // Now that we are done that, clear the saving flag and change the store
    this.saving = false; this.changeStore();
  }

If the store is not dirty or I am currently saving data, then this method becomes a no-op. I’ll just wait for the next time round. Then there is a definite process to follow.

  • Set up the flags to show the store is saving and push that out to the views
  • Get a list of the dirty tasks
  • Serialize each task and store it, then clear the dirty flag
  • Clear the saving flag and then push the changes out to the views

In this way, we can continue working and recording changes while the saving is happening. Each task is saved independently and asynchronously.

Showing Off Sync Status

I’ve got a component called components/TaskSyncStatus.jsx that shows off the state of the saving process. There are three states. If nothing is displayed, the store is clean (it doesn’t need saving) and saving is not in progress. If the store is dirty but not being saved, I put up an icon and if the store is saving, I put up a spinning icon.

Wrap Up

LocalForage is well worth a look if you need to store persistent data. It abstracts the various APIs and gives you a consistent method of accessing the data contained therein.

You need to think about storing data in pretty much any project. Using persistent storage locally allows you to prep for the eventual move to the cloud.

Building an ES6/JSX/React/Flux App – Part 3 – Authentication

Over the last two posts, I’ve delved into React and built my own Flux Light Architecture, all the while trying to implement the most basic of tutorials – a two-page application with client-side routing and remote data access. It’s now time to turn my attention to authentication. I’m – as ever – going to use my favorite authentication service, Auth0. Let’s first of all get authentication working, then work on how to use it.

New Actions

I need two new actions – one for logging in and one for logging out – to support authentication. This is defined in actions.js like this:

    static login(token, profile) {
        dispatcher.dispatch('LOGIN', { authToken: token, authProfile: profile });
    }

    static logout() {
        dispatcher.dispatch('LOGOUT');
    }

The Auth0 system returns a JSON Web Token and a profile object when you log in to it. These are passed along for storage into the store.

Store Adjustments

I’ve created a pair of new actions that carry data, so I need somewhere to store them. That’s done in the stores/AppStore.js file. First off, I need to initialize the data within the constructor:

    constructor() {
        super('AppStore');
        this.logger.debug('Initializing AppStore');

        this.initialize('pages', [
          { name: 'welcome', title: 'Welcome', nav: true, auth: false, default: true },
          { name: 'flickr', title: 'Flickr', nav: true, auth: false },
          { name: 'spells', title: 'Spells', nav: true, auth: true }
        ]);
        this.initialize('route', this.getNavigationRoute(window.location.hash.substr(1)));
        this.initialize('images', []);
        this.initialize('lastFlickrRequest', 0);
        this.initialize('authToken', null);
        this.initialize('authProfile', null);
    }

I also need to process the two actions – this is done in the onAction() method:

            case 'LOGIN':
                if (this.get('authToken') != null) {
                    this.logger.error('Received LOGIN action, but already logged in');
                    return;
                }
                if (data.authToken == null || data.authProfile == null) {
                    this.logger.errro('Received LOGIN action with null in the data');
                    return;
                }
                this.logger.info(`Logging in with token=${data.authToken}`);
                this.set('authToken', data.authToken, true);
                this.set('authProfile', data.authProfile, true);
                this.changeStore();
                break;

            case 'LOGOUT':
                if (this.get('authToken') == null) {
                    this.logger.error('Received LOGOUT action, but not logged in');
                    return;
                }
                this.logger.info(`Logging out`);
                this.set('authToken', null, true);
                this.set('authProfile', null, true);
                this.changeStore();
                break;

Both action processors take care to ensure they are receiving the right data and that the store is in the appropriate state for the action before executing it.

The UI

There were three places I needed work. The first was in the NavBar.jsx file to bring in a NavToolbar.jsx component:

import React from 'react';
import NavBrand from './NavBrand.jsx';
import NavLinks from './NavLinks.jsx';
import NavToolbar from './NavToolbar.jsx';

class NavBar extends React.Component {
    render() {
        return (
            <header>
                <div className="_navbar">
                    <NavBrand/>
                </div>
                <div className="_navbar _navbar_grow">
                    <NavLinks pages={this.props.pages} route={this.props.route}/>
                </div>
                <div className="_navbar">
                    <NavToolbar/>
                </div>
            </header>
        );
    }
}

The second was the Client/views/NavToolbar.jsx component – a new component that provides a toolbar on the right side of the navbar:

import React from 'react';
import Authenticator from './Authenticator.jsx';

class NavToolbar extends React.Component {
    render() {
        return (
          <div className="_navtoolbar">
            <ul>
              <li><Authenticator/></li>
            </ul>
          </div>
      );
    }
}

export default NavToolbar;

Finally, I needed the Client/views/Authenticator.jsx component. This is a Controller-View style component. I’m using the Auth0Lock library, which can be brought in through dependencies in package.json:

  "dependencies": {
    "auth0-lock": "^7.6.2",
    "jquery": "^2.1.4",
    "lodash": "^3.10.0",
    "react": "^0.13.3"
  },

You should also add brfs, ejsify and packageify to the devDependencies, per the Auth0 documentation. Here is the top of the Client/views/Authenticator.jsx file:

import React from 'react';
import Auth0Lock from 'auth0-lock';
import Logger from '../lib/Logger';
import Actions from '../actions';
import appStore from '../stores/AppStore';

class Authenticator extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            token: null
        };
        this.logger = new Logger('Authenticator');
    }

    componentWillMount() {
        this.lock = new Auth0Lock('YOUR-CLIENT-ID', 'YOUR-DOMAIN.auth0.com');
        this.appStoreId = appStore.registerView(() => { this.updateState(); });
        this.updateState();
    }

    componentWillUnmount() {
        appStore.deregisterView(this.appStoreId);
    }

    updateState() {
        this.setState({
            token: appStore.get('authToken')
        });
    }

I don’t like having the client ID and domain embedded in the file, so I’m going to introduce a local WebAPI to solve that. Ensure you swap in your own Auth0 settings here. Other than that minor change, this is the basic Controller-View pattern. Now for the rendering:

    onClick() {
        if (this.state.token != null) {
            Actions.logout();       // Generate the logout action - we will be refreshed
            return;
        }

        this.lock.show((err, profile, token) => {
            this.lock.hide();
            if (err) {
                this.logger.error(`Error in Authentication: `, err);
                return;
            }
            Actions.login(token, profile);
        });
    }

    render() {
        let icon = (this.state.token == null) ? 'fa fa-sign-in' : 'fa fa-sign-out';
        let handler = event => { return this.onClick(event); };

        return (
            <span className="_authenticator" onClick={handler}>
                <i className={icon}></i>
            </span>
        );
    }

The render() method registers a click handler (the onClick() method) and then sets the icon that is displayed based on whether the current state is signed in or signed out. The onClick() method above it handles showing the lock. Once the response is received from the Auth0 system, I initiate an action to log the user in. If the user was logged in, the click initiates the logout action.

There is a methodology (redirect mode in Auth0 lock) that allows you to show the lock, then the page will be refreshed with a new hash containing the token. You can then store the token and restore the original page. That is all sorts of ugly to implement and follow. I like this version for it’s simplicity. I store the state and values of the authentication in the store, use actions to store that data, but don’t refresh the page.

Checking Authentication

I have a page within this app right now that requires authentication called spells. It never gets displayed because the code in NavLinks.jsx has logic to prevent it. Let’s fix that now.

First, NavLinks.jsx needs a new boolean property called authenticated:

NavLinks.propTypes = {
    authenticated: React.PropTypes.bool.isRequired,
    pages: React.PropTypes.arrayOf(
            React.PropTypes.shape({
                auth: React.PropTypes.bool,
                nav: React.PropTypes.bool,
                name: React.PropTypes.string.isRequired,
                title: React.PropTypes.string.isRequired
            })
        ).isRequired,
    route: React.PropTypes.string.isRequired
};

I can also change the logic within the visibleLinks to check the authenticated property:

        let visibleLinks = this.props.pages.filter(page => {
            if (this.props.authenticated === true) {
                return (page.nav === true);
            } else {
                return (page.nav === true && page.auth === false);
            }
        });

Now, I need to ensure that the NavBar and the AppView bubble the authentication state down the tree of components. That means adding the authenticated property to NavBar (I’ll leave that to you – it’s in the repository) and including it in the NavLinks call:

<NavLinks pages={this.props.pages} route={this.props.route} authenticated={this.props.authenticated}/>

That also means, AppView.jsx must provide it to the NavBar. This is a little more extensive. First of all, I’ve updated the state in the constructor to include an authenticated property:

        this.state = {
            pages: [],
            route: 'welcome',
            authenticated: false
        };

That means updateState() must be updated to account for the new state variable:

    updateState() {
        let token = appStore.get('authToken');
        this.setState({
            route: appStore.get('route'),
            pages: appStore.get('pages'),
            authenticated: token != null
        });
    }

Finally, I can push this state down to the NavBar:

        return (
            <div id="pagehost">
                <NavBar pages={this.state.pages} route={this.state.route} authenticated={this.state.authenticated}/>
                <Route/>
            </div>
        );

With this code, the Spells link will only appear when the user is authenticated.

Requesting API Data

So far, I’ve created an application that can re-jig itself based on the authentication state. But it’s all stored on the client. The authentication state is only useful if you request data from a remote server. I happen to have a Web API called /api/spells that must be used with a valid Auth0 token. You can read about it in a prior post. I’m not going to cover it here. Suffice to say, I can’t get data from that API without submitting a proper Auth0 JWT token. The code in the repository uses User Secrets to store the actual secret for the Auth0 JWT that is required to decode. If you are using the RTM version of Visual Studio 2015, right click on the project and select Manage User Secrets. Your user secrets should look something like this:

{
  "JWT": {
    "Domain": "YOUR-DOMAIN.auth0.com",
    "ClientID": "YOUR-CLIENT-ID",
    "ClientSecret": "YOUR-CLIENT-SECRET"
  }
}

If you run the application and browse to /api/settings, you should see the Domain and ClientID. If you browse to /api/spells, you should get a 401 response.

I can now use the same technique I used when requesting the Flickr data. Firstly, create two actions – one for the request and one for the response (in actions.js):

    static requestSpellsData() {
        dispatcher.dispatch('REQUEST-AUTHENTICATED-API', {
            api: '/api/spells',
            callback: Actions.processSpellsData
        });
    }

    static processSpellsData(data) {
        dispatcher.dispatch('PROCESS-SPELLS-DATA', data);
    }

Then, alter the Store to handle the request and response. This is a place where the request may be handled in one store and the response could be handled in a different store. I have a generic action that says “call an API with authentication”. It then sends the data to whatever action I tell it to. If I had a “SpellsStore”, the spells store could process the spells data on the return. It’s this disjoint method of handling the API call and response that allows me to have stores that don’t depend on one another. I’ve added the following to the constructor of the stores/AppStore.js:

this.initialize('spells', []);

I’ve also added the following to the case statement in onAction():

            case 'REQUEST-AUTHENTICATED-API':
                if (this.get('authToken') == null) {
                    this.logger.error('Received REQUEST-AUTHENTICATED-API without authentication');
                    return;
                }
                let token = this.get('authToken');
                $.ajax({
                    url: data.api,
                    dataType: 'json',
                    headers: { 'Authorization': `Bearer ${token}` }
                }).done(response => {
                    data.callback(response);
                });

            case 'PROCESS-SPELLS-DATA':
                this.logger.info('Received Spells Data: ', data);
                this.set('spells', data);

Finally, I can adjust the views/Spells.jsx file to be converted to a Controller-View and request the data. I’ve already done this for the views/Flickr.jsx. You can check out my work on the GitHub repository.

I’ve done something similar with the Settings API. The request doesn’t require authentication, so I just process it. I also cache the results (if the settings have been received, I don’t need to ask them again). This data is stored as ‘authSettings’ in the store. I then added the authSettings to the state in the views/Authenticator.jsx component. I also need to trigger the settings grab – I do this in the views/Authenticator.jsx component via the componentWillMount() method:

    componentWillMount() {
        if (this.lock == null && this.state.settings != null) {
            this.lock = new Auth0Lock(this.state.settings.ClientID, this.state.settings.Domain);
        } else {
            Actions.requestSettingsData();
        }
        this.appStoreId = appStore.registerView(() => { this.updateState(); });
        this.updateState();
    }

I don’t want the authenticator to be clickable until the settings have been rendered, so I added the following to the top of the render() method:

    render() {
        // Additional code for the spinner while the settings are loaded
        if (this.state.settings == null) {
            return (
                <span className="_authenticator">
                    <i className="fa fa-spinner fa-pulse"></i>
                </span>
            );
        }

This puts a spinner in the place of the login/logout icon until the settings are received.

Wrap-up

One of the biggest differences between MVC and Flux is the data flow. In the MVC architecture, you have a Datastore object that issues the requests to the backend and somehow updates the model, that then informs the controller via a callback (since it’s async). It feels hacky. MVC really works well when the controller can just do the request to get the model from the data store and get the response back to feed the view. Flux feels right in the async front-end development world – much more so than the MVC model.

The Flux architecture provides for a better flow of data and allows the easy integration of caching algorithms that are right for the environment. If you want to cache across restarts of the application (aka page refreshes), then you can store the data into localStore. If you want to specify a server-side refresh (for example, for alerting), then you can integrate SignalR into the system and let SignalR generate the action.

As you can guess, I’m loving the Flux architecture. After getting my head around the flow of data, it became very easy to understand. Code you understand is much easier to debug.

As always, you can get my code on my GitHub Repository.

Building an ES6/JSX/React Flux App – Part 2 – The Flux

In the first part of this tutorial, I concentrated on React views. In fact, I didn’t do anything else. Except for a little bit of in-component interactivity, everything that resulted from those views was static DOM. I could have written a little bit of JavaScript inside the HTML page to get the same effect. Smaller applications like these seem to make the frameworks cumbersome, but they demonstrate core features in an isolated setting. React and Flux (and pretty much any other architecture, framework or library) really come into their own in larger applications.

The same is true of Flux. Flux is the architecture that goes along with React. It does the same job as MVC – an interactive page – but in a very different way. Flux is definitely not MVC, as you can see from the architecture diagram:

08192015-1

In a Flux architecture, the Dispatcher is a central co-ordination point. It receives actions and dispatches them to stores. Stores react to those actions, adjusting their data, before informing any dependent views of a change. The actions can come from anywhere – external events like AJAX loads as well as user events like clicks or changes.

Normally, I would go to a library to implement such an architecture. If I were in an MVC world, I would be getting AngularJS or EmberJS to assist. There are lots of libraries out there (Fluxxor, Reflux and Alt to name a few). They all implement the full Flux architecture, have great tutorials in written and video form and are full featured. However, I found them difficult to wrap my head around. That’s mostly because I was wrapping my head around Flux – the design pattern – and their library at the same time. I’m more interested in the design pattern.

So I wrote my own. I’m calling this “Flux Light”. It doesn’t implement some of the more cumbersome features of Flux. It’s written entirely in ES6 and it’s opinionated. It expects you to write your code in ES6 as well. It also expects no overlapping stores (i.e. one store does not depend on another). It expects to be bundled with browserify or similar. I make no apologies for this. It’s a learning exercise and nothing more. (Of course, if folks feel that it’s useful to them, let me know and I will publish it on npm). The code for the library is located in Client/lib in the repository. I’m going to show how to use it.

The Dispatcher

The Dispatcher is the center of the Flux architecture. It has a couple of requirements:

  • Components should be able to use dispatch() with an Action
  • Stores should be able to register for actions

All actions flow through the Dispatcher, so it’s code surface should be small and simple. This code is located in lib/Dispatcher.js. That is only the class though. You will want to initialize the dispatcher. Do this in Client/dispatcher.js like this:

import Dispatcher from './lib/Dispatcher';

var dispatcher = new Dispatcher({
  logLevel: 'ALL'
});

export default dispatcher;

The only options available are logging ones right now. I use the logLevel to set the minimal log level you want to see in the JavaScript console. The most common log levels will be ‘ALL’ or ‘OFF’. If you don’t specify anything, you will get errors only.

Actions

Actions are just calls into the dispatcher dispatch() method. I’ve got a class full of static methods to implement actions, located in Client/actions.js, like so:

import dispatcher from './dispatcher';

export default class Actions {
    static navigate(newRoute) {
        dispatcher.dispatch('NAVIGATE', { location: newRoute });
    }
}

I can use this class to generate actions. For example, I want to have the NAVIGATE action happen when I click on one of the navigation links. I can adjust the NavLinks.jsx file like this:

import React from 'react';
import Actions from '../actions';

class NavLinks extends React.Component {
    onClick(route) {
        Actions.navigate(route);
    }

    render() {
        let visibleLinks = this.props.pages.filter(page => {
            return (page.nav === true && page.auth === false);
        });
        let linkComponents = visibleLinks.map(page => {
            let cssClass = (page.name === this.props.route) ? 'link active' : 'link';
            let handler = event => { return this.onClick(page.name, event); };

            return (<li className={cssClass} key={page.name} onClick={handler}>{page.title}</li>);
            });

        return (
            <div className="_navlinks">
                <ul>{linkComponents}</ul>
            </div>
        );
    }
}

Here I tie the onClick method via an event handler to the click event on the link. That, in turn, issues a navigate action to the dispatcher via the Actions class.

Somewhere, I have to bootstrap the dispatcher. That’s done in the app.jsx file:

import React from 'react';
import dispatcher from './dispatcher';
import AppView from './views/AppView.jsx';

dispatcher.dispatch('APPINIT');

React.render(<AppView/>, document.getElementById('root'));

The AppStore

In my prior example, I was passing the pages and route down from the bootstrap app.jsx file. I’m now going to store that information in a Store – a flux repository for data. I’ve got a nice API for this. Firstly, there is a class you can extend for most of the functionality – lib/Store. You have to implement a constructor to set the initial state of the store and an onAction() method to handle incoming actions from the dispatcher.

The API for the Store contains the following:

  • Store.initialize(key,value) initializes a key-value pair in the store.
  • Store.set(key, value, [squashEvents=false]) sets a key-value pair in the store. Normally, a store changed event will be triggered. If you set squashEvents=true, then the store changed event is squashed, allowing you to set multiple things before issuing a store changed event.
  • Store.get(key) returns the value of the key in the store.
  • Store.storeChanged() issues a store changed event.
  • Store.registerView(callback) calls the callback whenever the store is changed. Returns an ID that you can use to de-register the view.
  • Store.deregisterView(id) de-registers a prior view registration.

Creating a store is simple now. You don’t have to worry about a lot of the details. For instance, here is my store/AppStore.jsx file:

import Store from '../lib/Store';
import find from 'lodash/collection/find';
import dispatcher from '../dispatcher';

class AppStore extends Store {

    constructor() {
        super('AppStore');
        this.logger.debug('Initializing AppStore');

        this.initialize('pages', [
          { name: 'welcome', title: 'Welcome', nav: true, auth: false, default: true },
          { name: 'flickr', title: 'Flickr', nav: true, auth: false },
          { name: 'spells', title: 'Spells', nav: true, auth: true }
        ]);
        this.initialize('route', this.getNavigationRoute(window.location.hash.substr(1)));
    }

    onAction(actionType, data) {
        this.logger.debug(`Received Action ${actionType} with data`, data);
        switch (actionType) {

            case 'NAVIGATE':
                let newRoute = this.getNavigationRoute(data.location);
                if (newRoute !== this.get('route')) {
                    this.set('route', newRoute);
                    window.location.hash = `#${newRoute}`;
                }
                break;

            default:
                this.logger.debug('Unknown actionType for this store - ignoring');
                break;
        }
    }

    getNavigationRoute(route) {
        let newRoute = find(this.get('pages'), path => { return path.name === route.toLowerCase(); });
        if (!newRoute) {
            newRoute = find(this.get('pages'), path => { return path.default && path.default === true; });
        }
        return newRoute.name || '';
    }
}

var appStore = new AppStore();
dispatcher.registerStore(appStore);

export default appStore;

The constructor uses initialize() to initialize two data blocks – the pages and the route from the original app.jsx. The onAction() method listens for NAVIGATE actions and acts accordingly.

At the end, I create a singleton version of the AppStore and register it with the dispatcher – this causes the dispatcher to send actions to this store.

The Controller-View

In the Flux architecture, there are two types of React components. Controller-Views are linked to one or more stores and use state to maintain and update their children. Other React components are not linked to stores and DO NOT USE STATE – they only use props.

Controller-Views need to do the following:

  • Call registerView on each store they are associated with when the component is mounted (use the componentWillMount() lifecycle method)
  • Call deregisterView on each store they are associated with when the component is about to be unmounted (use the componentWillUnmount() lifecycle method)

In my previous post, I created an AppView.jsx to use state with the start of a router. I can alter that to become a Controller-View:

import React from 'react';
import appStore from '../stores/AppStore';
import NavBar from '../views/NavBar';
import Welcome from '../views/Welcome';
import Flickr from '../views/Flickr';
import Spells from '../views/Spells';

class AppView extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            pages: [],
            route: 'welcome'
        };
    }

    componentWillMount() {
        this.appStoreId = appStore.registerView(() => { this.updateState(); });
        this.updateState();
    }

    componentWillUnmount() {
        appStore.deregisterView(this.appStoreId);
    }

    updateState() {
        this.setState({
            route: appStore.get('route'),
            pages: appStore.get('pages')
        });
    }

    render() {
        let Route;
        switch (this.state.route) {
            case 'welcome': Route = Welcome; break;
            case 'flickr': Route = Flickr; break;
            case 'spells': Route = Spells; break;
            default: Route = Welcome;
        }

        return (
            <div id="pagehost">
                <NavBar pages={this.state.pages} route={this.state.route}/>
                <Route/>
            </div>
        );
    }
}

export default AppView;

The constructor just sets some empty state variables. When the component is mounted, the view is registered with the store and the state is updated from the store. When the component is unmounted (or just before), the view is deregistered again. The function updateState() is the callback that the store uses to inform the view of an updated state.

In the render() function, I’ve expanded the number of routes to the full complement. This also matches the list defined in the AppStore. If you wanted to keep the definition of the pages in one place, you could issue an action from this component to set the pages, then let the state update them once they’ve gone through the system. You would not want to just set the pages within the store. That would most definitely not be flux-like.

To round out this sequence, I’ve added a couple of pages – Flickr.jsx and Spells.jsx – as simple static React components. You can get this code drop from my GitHub Repository.

Handling AJAX in a Flux Architecture

Let’s say I wanted to fill in the details of the Flickr page. This is designed to bring the first 20 images for a specific tag back to the page. To do that, I need to make an AJAX JSONP request to the Flickr API.

In a React world, I will do two actions. The first will be when the Flickr page comes into focus. I want to issue a “REQUEST-FLICKR-DATA” action at that point. This will cause the store to kick off the AJAX request. When the request comes back, the store will issue a “PROCESS-FLICKR-DATA” action with the data that came back. This ensures that all stores get notified of the AJAX request and response.

Why the store? The store is the central source of truth for all data within a Flux architecture. The views should not be requesting the data.

Why the second action? Well, in this simple application, we could use just one action – the request. However, let’s say you had another store that counted the number of in-flight AJAX requests – or one that did nothing but do AJAX requests (for example, to allow the inclusion of authentication tokens). You may have one store handling the request and one store handling the response.

To implement this, I first added the actions to my actions.js file:

import dispatcher from './dispatcher';

export default class Actions {
    static navigate(newRoute) {
        dispatcher.dispatch('NAVIGATE', { location: newRoute });
    }

    static requestFlickrData(tag) {
        dispatcher.dispatch('REQUEST-FLICKR-DATA', { tag: tag });
    }

    static processFlickrData(data) {
        dispatcher.dispatch('PROCESS-FLICKR-DATA', data);
    }
}

Then I altered the onAction() method within the stores/AppStore.js file:

            case 'REQUEST-FLICKR-DATA':
                let lastRequest = this.get('lastFlickrRequest');
                let currentTime = Date.now;
                let fiveMinutes = 5 * 60 * 1000;
                if ((currentTime - lastRequest) > fiveMinutes) {
                    return;
                }
                $.ajax({
                    url: 'http://api.flickr.com/services/feeds/photos_public.gne',
                    data: { tags: data.tag, tagmode: 'any', format: 'json' },
                    dataType: 'jsonp',
                    jsonp: 'jsoncallback'
                }).done(response => {
                    Actions.processFlickrData(response);
                });
                break;

            case 'PROCESS-FLICKR-DATA':
                this.set('images', data.items);
                break;

In this case, I only request the Flickr data if five minutes have elapsed. When the response comes back, I trigger another action. This is, in my case, processed just below the request by the PROCESS-FLICKR-DATA block. If five minutes have not elapsed, then no request is made and no changes to the page are made. You can flick back and forth between the welcome and flickr page all you want – it won’t change.

Of course, there was some setup required for this code to work:

import Store from '../lib/Store';
import find from 'lodash/collection/find';
import dispatcher from '../dispatcher';
import Actions from '../actions';
import $ from 'jquery';

class AppStore extends Store {

    constructor() {
        super('AppStore');
        this.logger.debug('Initializing AppStore');

        this.initialize('pages', [
          { name: 'welcome', title: 'Welcome', nav: true, auth: false, default: true },
          { name: 'flickr', title: 'Flickr', nav: true, auth: false },
          { name: 'spells', title: 'Spells', nav: true, auth: true }
        ]);
        this.initialize('route', this.getNavigationRoute(window.location.hash.substr(1)));
        this.initialize('images', []);
        this.initialize('lastFlickrRequest', 0);
    }

Don’t forget to add jquery to the list of dependencies in package.json or via npm install --save jquery.

Now that I have the actions and store sorted for the new data source, I can convert Flickr.jsx to a Controller-View and render the images that get loaded. I’m going to kick off the request in the constructor. Since I have a rudimentary cache going, it won’t hit the Flickr API badly. Here is the code in views/Flickr.jsx:

import React from 'react';
import Actions from '../actions';
import appStore from '../stores/AppStore';

class Flickr extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            images: [],
            tag: 'seattle'
        };

        Actions.requestFlickrData(this.state.tag);
    }

    componentWillMount() {
        this.appStoreId = appStore.registerView(() => { this.updateState(); });
        this.updateState();
    }

    componentWillUnmount() {
        appStore.deregisterView(this.appStoreId);
    }

    updateState() {
        this.setState({
            images: appStore.get('images')
        });
    }

    render() {
        let images = this.state.images.map(image => {
            let s = image.media.m.split('/');
            let fn = s[s.length - 1].split('.')[0];
            return (
                <div className="col-sm-6 col-md-3" key={fn}>
                    <a className="thumbnail"><img src={image.media.m}/></a>
                </div>
            );
        });

        return (
            <section id="flickr">
                <h2>Flickr</h2>
                <div className="row">{images}</div>
            </section>
        );
    }
}

export default Flickr;

There are a couple of things I could have done differently here. Firstly, I could have requested the flickr data only when the component was mounted. This version asks for the data when the component is created. I wanted to minimize those round trips to the Flickr API during testing and this seemed a reasonable way of doing it. Given that I have the cache functionality in the store, I could reasonably see moving the request to the componentWillMount() method.

I could have made the Flickr component just a regular component. This would have required me to change AppView so that it made the request and passed that down when the page was instantiated. I didn’t think this was a good idea. As the application expanded, I would have all sorts of extra code in the AppView. Making each “page” have state and be connected to a store seems much more reasonable to me.

Finally, I could have made the Flickr data its own store. In this application expands, you naturally want to have stores handle specific data. For instance, you might have a store that deals with “books” or “friends” or “images”. Inevitably, you will have a simple store that deals with navigation and authentication. So, yes, I see merit in creating another store called ImageStore in a larger application. It seemed overkill for this application.

You can get the code from my GitHub Repository.

Wrap Up

This is the end of the React/Flux version of the Aurelia tutorial, but not the end of my tutorial. I like to add authentication and monitoring to my applications as well, so I’ll be taking a look at those next.

This is a good time to compare for the four frameworks I have worked with. I’ve worked with Angular, Aurelia, Polymer and React/Flux now. Let’s discuss each one.

I felt Angular was heavy on the conventional use. It didn’t allow me to be free with my JavaScript. I felt that there was the Angular way and everything else was really a bad idea. Yes, it did everything I wanted, but the forklift upgrade (coming for v2.0) and the difficulty in doing basic things, not to mention the catalog of directives one must know for simple pages, meant it was heavier than I wanted to use.

Aurelia was a breath of fresh air in that respect. It worked with ES6, not against it. Everything is a class. However, the lack of data management right now, plus a relatively heavy-weight library on the download makes this a poor choice for simple applications. I suppose I could have done the same as I did here and used browserify to bundle everything together, but it isn’t easy.

Polymer is a third of a framework, in much the same way that React is a partial framework. It can’t stand alone. You need page routing and data management. These are, in the Polymer world, extra web components that you just download. Since there is no “import” system that allows for importing from standardized locations, you end up with a lot of hacking. Polymer will find a place, particularly when you consider the upcoming ES6-compatible MVC architectures like Angular-2 and Aurelia.

React/Flux is definitely focussed on large applications. Even my modest tutorial application (and not including the library code I wrote) was a significant amount of code. However, I can appreciate the flow of data and I understand that flow of data. That allows me to short-circuit the debugging process and go straight to the source of the problem. As the application grows, the heaviness of the framework coding becomes less of an issue.

I can see areas for improvement in the React/Flux code I wrote – some boilerplate that can be kicked out into classes all of their own. I like what I have here.

Mobile is another area that I am increasingly becoming interested in. With React, there is React Native – a method of using React code within an iOS application that compiles to a native iOS app. React is also much more usable in an Apache Cordova app – allowing Android and Windows Phone coverage as well. Angular works well with Apache Cordova (see the Ionic Framework). Aurelia does not work well with mobile apps yet. Polymer is “just another component”, but the polyfills that are necessary to make Polymer work on Apache Cordova are heavier than I expected.

Overall, I’ll continue watching React with great interest.

In my next post, I’ll cover authentication with my favorite authentication service – Auth0.

Building an ES6/JSX React/Flux App – Part 1 – the Views

One of the newer technologies on the JavaScript scene is Flux. It’s getting a lot of attention right now because it’s not MVC. It seems like every other framework was doing MVC or some variant thereof. Facebook (the instigators of Flux and it’s associated library – React) decided there was a better way for larger applications.

There are many articles on React and Flux – I like the introduction from Fluxxor – a library that implements the Flux architecture. However, here is the obligatory Flux architecture diagram:

08192015-1

In the Flux Architecture, there is a Dispatcher at the center of everything. The system creates Actions that are dispatched by the Dispatcher to the Stores (all the stores). Stores hold data. Not just one type of data, mind you – they could hold many types of data. The stores emit a “store changed” event when their data changes. Views listen for those changes and re-render appropriately. Those Views are inevitably React components, whose primary purpose is to minimize the DOM replacements that go on as these are slow.

In the proper Flux architecture, the Dispatcher and Stores have specific APIs and functionalities that need to be implemented. However, one can forego a lot of the code and get a much simpler (and smaller) app by simplifying and altering the API. If you use the Reflux library, for example, they forego the Dispatcher completely – insteadrelying on the actions to dispatch directly to the stores. The interesting thing about an architecture is that it is theory – the libraries implement the concrete examples.

So much for theory. I want to build an app that implements React and Flux. Before I do that, I need to know how to write React components and how to build a production workflow for an app that utilizes React. So today is all about learning the basics of React and setting up a build process.

Initializing the Project

I’m using an ASP.NET5 project for this. I could have used a Node/Express or Koa or any number of other web servers. Aside from my Web API (which comes in at the very end when I talk about authentication), I only need client-side functionality.

I’ve also added a Client directory and created an initial index.html file:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>An ES6 React/Flux Demo</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
    <link rel="stylesheet" href="bundle.css">
</head>
<body>
    <div id="root">... booting ...</div>
    <script src="bundle.js"></script>
</body>
</html>

I need a build system and I’m going to use Gulp as normal. I’ve added an NPM package.json file:

{
  "version": "1.0.0",
  "name": "react-demo",
  "private": true,
  "devDependencies": {
    "gulp": "^3.9.0",
    "gulp-less": "^3.0.3"
  }
}

I’ve also created a Gulpfile.js:

var gulp = require('gulp'),
    less = require('gulp-less');

var config = {
    src: './Client',
    dest: './wwwroot'
};

var files = {
    html: config.src + '/**/*.html',
    less: config.src + '/style/bundle.less'
};

gulp.task('build', ['style', 'html']);

gulp.task('html', function ()
{
    return gulp.src([files.html]).pipe(gulp.dest(config.dest));
});

gulp.task('style', function ()
{
    return gulp.src([files.less])
        .pipe(less())
        .pipe(gulp.dest(config.dest));
});

Once this was done, I bound the build task to the Before Build step in the Task Runner Explorer. Don’t worry about the bundle.js for now – I’ll get on to that later. If you run this project (just to see it working), you should get a browser window with a booting message displayed.

You can get my starting point from my GitHub Repository.

A Simple React Component

I’m going to write what is possibly the simplest react component ever. It just pushes out a HTML DOM. I’m going to use it to provide a title for my website. The file is located in Client/views/NavBrand.jsx – note the use of the JSX extension – that’s very important, as you will see in a moment. If you are using Visual Studio 2015 (and I suggest you do!), then use item template JSX File.

import React from 'react';

class NavBrand extends React.Component {
  render() {
    return (
      <div className="_navbrand">
        <div className="valign">
          React Demo
        </div>
      </div>
    );
  }
}

export default NavBrand;

This made me do a double-take when I first saw it. A JavaScript function is returning HTML. Actually, it’s not – there are some visual clues, such as using className instead of the normal class to specify the CSS class. There are other differences:

  • If you use label for="", the for becomes htmlFor
  • If you have a HTML element that is not terminated, you need to use /> (e.g. <img />)

There are also other differences, but I’ll get to them later. Unfortunately, Visual Studio 2015 still doesn’t like ES6 + JSX syntax (and it still has problems with ES6 in general). Atom is much better in this regard, so if you are following along on a Mac or using Node/Express, you may want to switch to Atom.

I’ve also got some style in Client/style/NavBrand.less and I’ve included that file in the bundle.less file. I do this for every single React component I write, so I’m not going to mention it again. Just be sure to pick up the less stylesheets from the repository.

This only defines the React component. I also need to use it. To do this, I’m going to create a Client/app.jsx file that I’ll use as a bootstrap:

import React from 'react';
import NavBrand from './views/NavBrand.jsx';

React.render(<NavBrand/>, document.getElementById('root'));

Building The System

I’ve got a lot going on here. My code is ECMAScript 6 and has JSX embedded in it. I also use modules that need to be dealt with. I could just write this for SystemJS (and I’ve blogged about that). Instead I’m going to use a production build system based on browserify. Browserify is a system for bundling all the libraries and JS code you use into one bundle file. All I have to do is load the libraries I want as dependencies in package.json and then run browserify. I still need to transform the ES6 and JSX code into ES5.1 for most browsers. Fortunately, there is a plugin called babelify that uses Babel for that purpose.

Since this is a production workflow, I want to bring eslint into the mix for pre-run checking. Eslint also has a plugin for React/JSX, so I’ll use that. It’s important to note here – Visual Studio 2015 doesn’t seem to like mixing ES6 and JSX. You get a lot of red-squiggly lines for perfectly valid code. As a result, you need eslint to ensure you don’t make syntax errors prior to publishing your code.

These are pretty much recipes, so I’m just copying from someone else (and I forget who, but everyone seems to use the same recipe). Here is the package.json:

{
  "version": "1.0.0",
  "name": "react-demo",
  "private": true,
  "devDependencies": {
    "babelify": "^6.1.3",
    "browserify": "^11.0.0",
    "eslint": "^0.24.1",
    "eslint-plugin-react": "^3.0.0",
    "gulp": "^3.9.0",
    "gulp-eslint": "^0.15.0",
    "gulp-less": "^3.0.3",
    "gulp-rename": "^1.2.2",
    "vinyl-source-stream": "^1.1.0"
  },
  "dependencies": {
    "react": "^0.13.3"
  }
}

I also need a task in the gulpfile.js:

var gulp = require('gulp'),
  browserify = require('browserify'),
  eslint = require('gulp-eslint'),
  less = require('gulp-less'),
  rename = require('gulp-rename'),
  source = require('vinyl-source-stream');

  // Previously discussed parts not included

gulp.task('bundle', [ 'eslint', 'copyhtml' ], function () {
  var bundler = browserify({
    extensions: ['.js', '.jsx'],
    transform: ['babelify'],
    debug: true
  });

  return bundler
    .add(files.entry)
    .bundle()
    .on('error', function(err) {
      console.error(err.toString());
    })
    .pipe(source(files.entry))
    .pipe(rename('bundle.js'))
    .pipe(gulp.dest(config.dest));
});

I also need an .eslintrc file with the following contents (just create a JSON file with the name .eslintrc):

{
  "ecmaFeatures": {
    "modules": true,
    "jsx": true
  },
  "env": {
    "browser": true,
    "es6": true
  },
  "plugins": [
    "react"
  ],
  "rules": {
    "quotes": [ 2, "single", "avoid-escape" ],
    "react/display-name": [ 1, { "acceptTranspilerName": true }],
    "react/jsx-boolean-value": 1,
    "react/jsx-no-undef": 1,
    "react/jsx-quotes": 1,
    "react/jsx-sort-prop-types": 1,
    "react/jsx-sort-props": 0,
    "react/jsx-uses-react": 1,
    "react/jsx-uses-vars": 1,
    "react/no-danger": 1,
    "react/no-did-mount-set-state": 1,
    "react/no-did-update-set-state": 1,
    "react/no-multi-comp": 1,
    "react/no-unknown-property": 1,
    "react/prop-types": 1,
    "react/react-in-jsx-scope": 1,
    "react/require-extension": 1,
    "react/self-closing-comp": 1,
    "react/sort-comp": 1,
    "react/wrap-multilines": 1
  }
}

The majority of the rules are ripped from an example in the eslint-plugin-react documentation. I’ve made some changes to suit my coding style and to support ES6.

Running the project will give you a simple piece of text. You no longer have the booting message. Instead you have a React Demo statement. That’s coming from the simple component I developed earlier.

You can get the build system plus this first component from my GitHub Repository.

React Components inside React Components

React is like many other web component technologies. You can embed components inside of components. For example, let’s say I want a NavBar.jsx component:

import React from 'react';
import NavBrand from './NavBrand.jsx';

class NavBar extends React.Component {
    render() {
        return (
            <header>
                <div className="_navbar">
                    <NavBrand/>
                </div>
                <div className="_navbar _navbar_grow">

                </div>
                <div className="_navbar">

                </div>
            </header>
        );
    }
}

export default NavBar;

I’m leaving two of the DIV elements blank, for later expansion. You can clearly see the NavBrand element embedded inside of the JSX that I am returned for the NavBar element. You can adjust the app.jsx file to bring in this component instead of NavBrand to see it in action. You can, of course, get the code from my GitHub Repository.

Reusable Components – Props

Let’s say I have a set of links I want to display. The links are defined (in app.jsx) like this:

var pages = [
      { name: 'welcome', title: 'Welcome', nav: true, auth: false, default: true },
      { name: 'flickr', title: 'Flickr', nav: true, auth: false },
      { name: 'spells', title: 'Spells', nav: true, auth: true }
];
var route = 'welcome';

I could then pass these variables down into a component like this (also in app.jsx):

React.render(<NavBar pages={pages} route={route}/>, document.getElementById('root'));

These are Properties and they appear in this.props in a React component. I need to adjust my NavBar.jsx file to account for these:

import React from 'react';
import NavBrand from './NavBrand.jsx';
import NavLinks from './NavLinks.jsx';

class NavBar extends React.Component {
    render() {
        return (
            <header>
                <div className="_navbar">
                    <NavBrand/>
                </div>
                <div className="_navbar _navbar_grow">
                    <NavLinks pages={this.props.pages} route={this.props.route}/>
                </div>
                <div className="_navbar">

                </div>
            </header>
        );
    }
}

export default NavBar;

I’ve added a new component called NavLinks that takes the properties that NavBar received. Now I need to write Client/views/NavLinks.jsx:

import React from 'react';

class NavLinks extends React.Component {
    render() {
        let visibleLinks = this.props.pages.filter(page => {
            return (page.nav === true && path.auth === false);
        });
        let linkComponents = visibleLinks.map(page => {
            let cssClass = (page.name === this.props.route) ? 'link active' : 'link';
            return (<li className={cssClass} key={page.name}>{page.title}</li>);
        });

        return (
            <div className="_navlinks">
                <ul>{linkComponents}</ul>
            </div>
        );
    }
}

export default NavLinks;

A few notes here. You can use any variable within JSX – just include it in curly braces. Note how I do iteration here – Aurelia has repeat.for, Angular has ng-repeat. React just uses JavaScript so I don’t have to learn a whole bunch of new syntax, nor do I need an extra plug-in just to iterate. I do, however, need to ensure I define a key on iterated elements. Normally, React will define a default key on all elements so that it can refer to a specific key. In the case of iterators, it can’t, so you have to do it instead.

If you build and run this project, you will get a nice list of all the pages that don’t require authentication, according to the object we pass into the root element (the NavBar in app.jsx). However, you will also note that there are errors from eslint:

08152015-1

React expects you to define the types of properties that a component can accept. The route property is a string and the pages property is a complex object. To define the property, you need to add a static object called propTypes to the class. PropTypes defines the shape of the properties that you accept. This is the way I do it:


NavLinks.propTypes = {
    pages: React.PropTypes.arrayOf(
            React.PropTypes.shape({
                auth: React.PropTypes.bool,
                nav: React.PropTypes.bool,
                name: React.PropTypes.string.isRequired,
                title: React.PropTypes.string.isRequired
            })
        ).isRequired,
    route: React.PropTypes.string.isRequired
};

Put this block right above the export statement. You can do all sorts of validation and be very prescriptive with the shape of the properties coming in. Check out the docs for the full syntax.

Since the properties for NavBar are identical to the properties for NavLinks, you can cut and paste the object to the NavBar object as well to get rid of the warnings. The code, in case you got lost, is on my GitHub Repository.

State and the Welcome Page

In the Aurelia tutorial there was a Welcome page with a form and some dynamic elements. I’m going to create two things. Firstly, I’m going to create an AppView.jsx component that represents the complete page. Here is the code:

import React from 'react';
import assign from 'lodash/object/assign';
import NavBar from '../views/NavBar';
import Welcome from '../views/Welcome';

class AppView extends React.Component {
    constructor(props) {
        super(props);

        this.state = this.props;
    }

    render() {
        let Route;
        switch (this.state.route) {
            case 'welcome': Route = Welcome; break;
            default: Route = Welcome;
        }

        return (
            <div id="pagehost">
                <NavBar pages={this.state.pages} route={this.state.route}/>
                <Route/>
            </div>
        );
    }
}

AppView.propTypes = {
    pages: React.PropTypes.arrayOf(
            React.PropTypes.shape({
                auth: React.PropTypes.bool,
                nav: React.PropTypes.bool,
                name: React.PropTypes.string.isRequired,
                title: React.PropTypes.string.isRequired
            })
        ).isRequired,
    route: React.PropTypes.string.isRequired
};

export default AppView;

Don’t forget to also alter app.jsx to render the AppView instead of the NavBar. In order to compile this, I’m using a lodash function to provide a basic object deep-copy capability, so I need to my list of dependencies in package.json. Lodash is a collection of utility functions. The assign function just copies my properties into a new thing called state.

Aside from the state thing, I’m setting this up to be a router for my page – as can be seen in the render() method. I only have one route right now, but I can add more routes as they become available.

So, why two areas to store data? Properties are defined to be immutable – you set them once and walk away. They don’t get changed within the component. State can be changed. This means I can use it to cause changes in the rendered component. Obviously, the example above (while relevant later on) is a totally useless change. I’m using state instead of props – big deal.

However, if you remember the Welcome Page from the Aurelia Tutorial, you will know we need interactivity for the page. Here is the code for Welcome.jsx:

import React from 'react';

class Welcome extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            firstname: 'John',
            lastname: 'Doe'
        };
    }

    onSubmit() {
        alert(`Hello ${this.fullname}`); // eslint-disable-line no-alert
    }

    onChange() {
        this.setState({
            firstname: React.findDOMNode(this.refs.fn).value,
            lastname: React.findDOMNode(this.refs.ln).value
        });
    }

    get fullname() {
        return `${this.state.firstname} ${this.state.lastname}`;
    }

    render() {
        let submitHandler = event => { return this.onSubmit(event); };
        let changeHandler = event => { return this.onChange(event); };

        return (
          <section id="welcome">
            <h2>Welcome</h2>

            <form role="form" onSubmit={submitHandler}>
              <div className="form-group">
                <label htmlFor="firstname">First Name</label>
                <input className="form-control" onChange={changeHandler} placeholder="First Name" type="text" value={this.state.firstname} ref="fn"/>
              </div>
              <div className="form-group">
                <label htmlFor="lastname">Last Name</label>
                <input className="form-control" onChange={changeHandler} placeholder="Last Name" type="text" value={this.state.lastname} ref="ln"/>
              </div>
              <div className="form-group">
                <label>Full Name</label>
                <p className="help-block">{this.fullname}</p>
              </div>
              <button type="submit" className="btn btn-default">Submit</button>
            </form>
          </section>
      );
    }
}

export default Welcome;

Let’s go through this slowly. The constructor sets up our initial state. I’m setting a firstname and a lastname. Next, I define an event handler that will get called when I click on Submit and an event handler when I change the text in one of the text boxes. I’ll come back to the change handler later. I’ve got a computed property next – this is used in both the submit handler to alert “Hello My Name” and within the page render.

Talking of the page render, that’s actually not too complex. Just take it slow and you will see that the JSX is practically identical to the HTML code used in the Aurelia tutorial. However, there is an interesting aspect to those input boxes. The ref attribute is not normal HTML. It’s used by React to find a specific node within this component. It’s similar to the this.$.id in Polymer, but it doesn’t use the id (which can be different). When I get to the change handler, I can use React.findDOMNode to find an element by ref.

On running this project, note the following:

  • Altering either text box will alter the computed field for Full Name
  • Pressing Submit will pop up an alert with the full name

This is a pretty basic in-component interactivity example. You can find the code on my GitHub Repository. I’ve also added a NavToolbar component to finish off the NavBar – it’s a static component for right now, just like NavBrand, so it should be familiar territory.

Wrap Up

There are obvious parallels to draw here between React and Polymer. Both are component technologies and both can render complete pages using sub-components. Both have a level of interactivity that can be built in via private event handling. Both can encapsulate the DOM elements within the component so that they can be referenced easily. Both have a full set of lifecycle functions that can be utilized to easily handle DOM behavior.

React doesn’t require any special features from the browser – it works in any modern browser. Polymer has to polyfill for missing browser features – Shadow DOM, Custom Elements, Templates, and so on. React works fine with ES6 out of the box. Polymer isn’t really ready for ES6 yet. In my tests, React was significantly faster on large DOM changes. And that is the defining thing here. React is fast. For my simple tutorial, that’s not really important. However, transition to a larger project and you really notice the slow down in the DOM when you have to re-draw complete pages.

In the end, it’s a matter of personal preference. Both are young technologies. I suspect that if you are using an MVC architecture and you want components, you will gravitate towards Polymer since they can be easily included. If you want to use a Flux architecture, then you will use React components.

In the next post, I’ll cover a “Flux” architecture and finish off the Aurelia tutorial pages with a full Flux implementation.

ASP.NET, ES2015, React, SystemJS and JSPM

I’ve started investigating a relative newcomer to the JavaScript library, but one that is making a lot of noise. That library is React. But when I combined this with ASP.NET, I found the build processes confusing. There just isn’t a good recipe out there that allows you to write React/JSX components in ECMAScript 6 and get anything like the debugging you want. You lose the source map and any association with the actual source – not too good for the debugging environment. So how do you handle this?

Let’s rewind a bit.

What is React again? It’s a component technology. It occupies the same space as Polymer in that respect, although with vastly differing implementation details. It handles web-based components. It’s got various advantages and disadvantages over other component technologies, but it does the same thing at the end of the day.

I’m not going to go over yet another React tutorial. Really, there are plenty of them even if you don’t know much web dev, including tutorials on React and ES6.

Why am I learning them? Isn’t Polymer enough? Well, no. Firstly, React and Flux are a framework combination that I wanted to learn. I want to learn it mostly because it isn’t MVC and I wanted to see what a non-MVC framework looked like. Flux is the framework piece and React provides the views. Then there are things like React Native – a method of making mobile applications (only iOS at the moment) out of React elements. It turns out to be extremely useful.

As a module system, I like to use jspm. It’s optimized for ES6. So that was my first stop. Can I use jspm + ES6 + JSX + React all in the same application. Let’s make a basic Hello World React app using an ASP.NET based server in Visual Studio.

Step 1: Set up the Server

There really isn’t anything complicated about the server this time. I’m just adding Microsoft.AspNet.StaticFiles to the project.json:

{
  "webroot": "wwwroot",
  "version": "1.0.0-beta5",

  "dependencies": {
    "Microsoft.AspNet.Server.IIS": "1.0.0-beta5",
    "Microsoft.AspNet.Server.WebListener": "1.0.0-beta5",
    "Microsoft.AspNet.StaticFiles": "1.0.0-beta5"
  },

This isn’t the whole file, but I only changed one line. The Startup.cs file is similarly easy:

using Microsoft.AspNet.Builder;
using Microsoft.Framework.DependencyInjection;

namespace WebApplication1
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
        }

        public void Configure(IApplicationBuilder app)
        {
            app.UseStaticFiles();
        }
    }
}

This gets us a web server that serves up the stuff inside wwwroot.

Step 2: Install Libraries

Next is jspm. Run jspm init like I have shown before. Then run:

jspm install react npm:react-dom jsx

This will install the ReactJS library and the JSX transformer for us. I’m using v0.14.0-beta1 of the ReactJS library. They’ve just made a change where some of the rendering code is separated out into a react-dom library. That library hasn’t made it into the JSPM registry yet, so I have to specify where it is.

Step 3: Write Code

First off, here is my wwwroot/index.html file:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World with React</title>
</head>
<body>
    <div id="root"></div>

    <script src="jspm_packages/system.js"></script>
    <script src="config.js"></script>
    <script>System.import("app.js!jsx");</script>
</body>
</html>

Note the !jsx at the end of the System.import statement. That tells SystemJS to run the file through the JSX transformer first. Now, let’s write wwwroot/app.js:

import React from "react";
import ReactDOM from "react-dom";

class HelloWorld extends React.Component {
    render() {
        return (<h1>Hello World</h1>);
    }
}

ReactDOM.render(<HelloWorld/>, document.getElementById("root"));

Don’t try this on any version of React prior to v0.14.0-beta1. As I mentioned, there are two libraries now – react for creating react components and react-dom for rendering them. You need both.

Step 4: Debug Code

This is a debuggers dream. I can see the code and the DOM side-by-side in the browser:

blog-08132015-1

Yep – that’s the original code. The JSX code has been transformed into JavaScript, but the ES6 code is right there. That means I can alter it “in-situ”, set break points, and generally work with it. If an exception occurs, it points at the original source code.

I wouldn’t want to ship this code. When you look at it, this small HelloWorld project loads 2.8MB and over 230 requests with a delay of 4.4 seconds (on localhost!) – just to get one React component rendered. I’d definitely be using Webpack or Browserify on a production site. But this is great for debugging.

Step 5: Code Control – Separate Components

Let’s say I wanted to give HelloWorld its own file. Code organization is important. It’s realatively simple with SystemJS. Just place the following code in wwwroot/components/HelloWorld.js:

import React from "react";

export default class HelloWorld extends React.Component {
    render() {
        return (<h1>Hello World</h1>);
    }
}

This is a copy of the original code, made into an ES6 module. Now I can alter the app.js file accordingly:

import React from "react";
import ReactDOM from "react-dom";

import HelloWorld from "./components/HelloWorld.js!jsx";

ReactDOM.render(<HelloWorld/>, document.getElementById("root"));

Final Notes

The Visual Studio editor is not doing me any favors here. I get errors all over the place. However, I can use this same technique in Visual Studio Code (which handles this syntax better), Atom and other places. This, however, is a great step towards debugging React code in a browser.

MVC, MVVM and Frameworks

I’ve been writing a whole bunch about MVC architectures – client side and server side.  But I hit a problem.  You see, MVC and MVVM are pretty simple concepts.  Here is a typical diagram that I see when looking at MVC descriptions:

blog-08012015-1

It’s nice and simple.  The controller loads the model and passes some form of data to the View.  The problem is this – where is the user and where is the data?  How do these actually interact?  This is actually a key point in understanding the architecture and the place that frameworks – any framework – occupies in the architecture.  I think the following is a much more representative architectural diagram:

blog-08012015-2

This makes more sense to me.  The user submits a request to a dispatcher.  The dispatcher decides which controller to pass the request to.  The controller asks the adapter to give it one or more models to complete the request.  In the case of MVVM, these models are transitioned into a View-Model, usually through some sort of data binding.  This new model (or view-model) is passed into the View rendering system, which renders the appropriate view and kicks it back to the core dispatcher so that the dispatcher can respond to the user.

It’s much more messy than the plain MVC (or MVVM) design pattern.  However, it’s implementable and I can see the pieces I need to implement in order to achieve the desired web application.  This architecture can be implemented on the client side or the server side and both sides have frameworks that assist.

Frameworks provide some sort of functionality that allow you to ignore the boiler-plate code that inevitably comes with writing such an architecture.  Most frameworks have some sort of dispatcher (normally called a router, but they do much more than that) and most frameworks have some sort of adapter logic (mostly called an ORM or Object Relational Mapper).  In between, frameworks enforce a pattern for controllers, models and views that can be used to enforce consistency across the application.

On the server side, I have two go-to languages – C# and JavaScript.  I use ASP.NET as my framework of choice on the C# server side.  I can map my visual directly to ASP.NET:

  • ASP.NET provides the dispatcher, with an ability to configure a route map in it’s startup class.
  • The Controller class can be inherited to create custom controllers
  • The Model is a plain-old class
  • The View is handled by Razor syntax
  • The Adapter is generally handled by Entity Framework.

For server-side JavaScript, the mapping is a little more messy:

I haven’t really gotten into Models and Adapters, although I can see libraries such as Mongoose (for MongoDB) playing a part there.  However, there are Node/Express MVC frameworks out there – I want to investigate Locomotive and SailsJS at some point, for example.

On the client side, things are definitely more messy.  There are a host of different frameworks – Angular, Aurelia, Ember, Knockout, Meteor, React / Flux, along with a host of others.  I’ve found the TodoMVC site to have a good list of frameworks worth looking at.  Some of these are being upgraded to handle ES2015 syntax, some are already there and some are never going to be there.

One thing to note about frameworks.  They are all opinionated.  ASP.NET likes the controllers to be in a Controllers namespace.  Angular likes you to use directives.  Aurelia likes SystemJS and jspm.  Whatever it is, you need to know those opinions and how they will affect things.

The web isn’t the only place one can use frameworks.  The MVC architecture is not limited to web development – it’s constant across applications of any complexity.  For example, you can see MVC in WinForms, Mobile applications, Mac OSX Applications and Linux Applications.

I want my application to be rendered client-side, which means I need to take a look at client-side frameworks.  My working list is:

I’m not going to bother with Backbone, Meteor, Knockout or any other older or smaller framework.  This is my own time and I don’t want to spend a ton of time on investigation.  I pretty much know what Aurelia can provide.  To investigate the others I needed a small site I could implement – something that wasn’t “just another task organizer” (TodoMVC).  To that end, I decided to create a three page application.

  • Page 1 – the home page – will get loaded initially and contain a Polymer-based carousel
  • Page 2 – a linked page – will load data from the Internet (the Flickr example from the Aurelia app)
  • Page 3 – an authenticated page – will load data from the local server if the user is authenticated

In addition to the three pages, I’m going to ensure that the navigation is separated logically from the actual pages and that – where possible – the pages are written in ES2015.  I want separation of concerns, so I expect the models to be completely separate from the views and controllers.

Each one will be implemented on top of a Node/ExpressJS server that serves up just the stuff needed.  In this way, I will be able to see the install specifics.  You can see my starter project on my GitHub Repository.  I hope you will enjoy this series of blog posts as I cover each framework.