January 15, 2016

Getting Started With Flux And React

Who is This Blog For?

In this blog, we are going to give an introduction to React with Flux by using a sample project — creating a “To Do” list. The steps that we’ll go into will require a basic understanding of Javascript and web concepts. The same code that will we be using can be found here: https://github.com/mahesh-singh/justdo

Before we get into the code, we need some background information of Flux and React, which are both independent technologies.

What is Flux?

Flux is a Javascript architecture or pattern for UI which runs on a unidirectional data flow and has a centralized dispatcher. It is useful when your project has dynamic data and you need to keep the data updated in an effective manner. It was created by Facebook, and complements React as view. This model is used to ease maintenance. It has three primary components: Views, Stores, and Dispatcher. As the MVC application grows, we find many numbers of views as models, which are all talking to each other, making it difficult to manage and debug.

Two-Way binding

Two way binding

 

Unidirectional

Unidirectiona binding

Action: Action describes user interaction that occurred in a component, such as a user clicking a button.
Dispatcher: Dispatcher methods are invoked by an action component. This emits an event with data that needs to go to a store, which is a singleton registry.
Store: The store listens to certain events from the dispatcher. When it listens to an event from the dispatcher, it will then modify its internal data and emit a different event for views.
View: Views are typically a react component. Views get data from the store and set up a listener to refresh itself when the store emits any changed events.

What is React?

React is a lightweight and fast component library created and used by Facebook. It’s a view layer that can help you to create pluggable components. Since it just focuses on the view layer, it’s easy to learn and use with other Javascript frameworks.

In other component libraries, like AngularJS, we use JavaScript inside HTML with the help of directives. React has the opposite approach: it uses HTML inside JavaScript. At first glance, it may seem ugly or you may find the separation to be concerning, but as you start to use it you will find it to be worthwhile.

In React we use “JSX” to create HTML. “JSX” is optional, but it gives you more readability and is easy to maintain and debug, as well as easy for designers to change. However, browsers don’t understand “JSX,” so it’s converted into plain JS when rendered on a browser.

var createuserrow= function(user){
    return(
        <tr key={user.id}>
            <td>{user.name}</td>  //This is JSX looks like html
        </tr>
    );
}

Updating DOM is an expensive task, which is why React created an abstraction above DOM called virtual DOM. React uses virtual DOM concepts and compares Old DOM with new look of DOM stored in memory when any value changes. It also updates the changed part only in the place where the change takes place. instead of rewriting the entire DOM again, which is why React is notably faster that any other component library. We do not need to make any code changes for React to use this feature automatically. Additionally, virtual DOM allows rendering on a server where no DOM exists at all, and provides flexibility.

React also supports Isomorphic rendering that makes it search engine friendly and gives a better overall user experience. In another component library that loads the complete DOM on client and only gets data from API, a user will only see a loading screen or a blank screen once the data comes from the server and the client Javascript is rendering. A different component library also doesn’t give us DOM from the server, which makes it hard to a search engine to index it.

React does not support two-way binding, unlike other component libraries, like AngulaJS and Knockout, that use two-way binding. Two-way binding is useful but it has the risk of being unpredictable. When the UI is changed in two-way binding, it triggers a corresponding model change, which will trigger another model or other UI changes. This integration becomes hard to predict for large applications and is difficult to debug.

Why React?

There are several reasons to use React as a component library:

  • Speed: React uses virtual DOM concepts and updates only parts that have been changed by comparing the DOM to the stored memory, which makes it notably faster in comparison to other component libraries. It eliminates layout trash by using virtual DOM.
  • Scale: It can scale to a large UI because it is very efficient in how and when to manipulate the DOM.
  • Composable: You can easily nest a component inside of another component and pass the data to the child component via props.
  • Pluggable: Because React is a view layer, it can be used with any technology.
  • Isomorphic Friendly: React does not depend on the DOM to render. Instead, it avoids repeating code on both the client side and the server.
  • Simple: React is small and doesn’t have many moving components, so it’s easy to learn.
  • Batten Proven: React is already being used by big companies like Facebook, Paypal, and Yahoo.

Development Environment Setup

Most of the technologies we are setting up here are not required to work with React and Flux, but will give you a better and easier work environment. It will also be helpful to get rapid feedback when you are building your project.

Technologies used in sample project

  • NPM: Stands for Node Package Manager. This efficiently manages several Javascript frameworks.
  • Bower: This is used to manage all packages.
  • React: This is used for component design.
  • Flux: This is used for data flow management.
  • Browserify: This is used to bundle all CSS and Javascript files so as to reduce the number of HTTP requests.
  • Gulp: This is the task runner for development, and glues all of the above technologies together.

To install NPM, we need to install “node.js” installer because NPM is a part of a node.

Project Setup on Window:

  1. Install Python. To do so, go to https://www.howtogeek.com/197947/how-to-install-python-on-windows/ and follow the steps listed.
  2. Download the “node.js” Window Installer from https://nodejs.org/en/download/ and run it
  3. Restart your computer.
  4. Open the command prompt and run the command node –v to check that the node has been installed properly.
  5. Open the command prompt and navigate to the folder where the project file is present.
  6. Run the command NPM to install -g Bower.
  7. Once the Bower installation is complete, run the command Bower install to install the decencies resolved through Bower.
  8. Run the command NPM install to download and install the dependent NPM packages.
  9. Run the command Gulp to build the project
  10. Run the command Python app.py to run the server
  11. Access the URL you received from running the above command. You will be able to see the following page.

Screen shot

Code Walk Through

To open the project, you can use any text editor with which you are familiar. We are using Sublime text. When you open the project, you will find the structure shown in below image. The “main.js” file inside the “Static > Scripts > JS” folder is the entry point of code. At the top of the main.js file are two “require” syntax which will use the React component. In this code, the “JustDoApp” component is rendered.

Screen shot

This component is defined in “app.react.js” and calls on the nested “searchsection” component and the “projectsection” component. All of the React components are defined inside of the “component” folder.

var SearchSection = require('./SearchSection.react')
var ProjectSection = require('./ProjectSection.react');

var React = require('react');
var ProjectApi = require('../utils/ProjectApi')



var JustDoApp = React.createClass({
    componentDidMount: function() {
        ProjectApi.getAllTasks();

    },

    render: function () {
        return (
                <div id="main">
                    <SearchSection/>
                    <ProjectSection/>
                </div>
            );
    },

});

module.exports = JustDoApp;

The “searchsection” and “projectsection” components are defined in “SearchSection.react.js” and “ProjectSection.react.js” respectively.

var React = require('react');
var JustDoActions = require('../actions/JustDoActionCreator');

var SearchSection = React.createClass({
    showTaskEditor:function(){
        JustDoActions.updateTaskEditorVisibility(true); 
    },
    render: function () {
        return (
                        <nav className="navbar navbar-default">
                            <div className="container-fluid">
                                <div className="navbar-header">
                                    <button type="button" className="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                                        <span className="sr-only">Toggle navigation</span>
                                        <span className="icon-bar"></span>
                                        <span className="icon-bar"></span>
                                        <span className="icon-bar"></span>
                                    </button>
                                    <a className="navbar-brand" href="#">Just Do</a>
                                </div>

                                <div className="collapse navbar-collapse" id="bs-example-navbar-collapse-1">

                                    <form className="navbar-form navbar-left" role="search">
                                        <div className="form-group">
                                            <input type="text" className="form-control " placeholder="Search"/>
                                        </div>
                                        <button type="submit" className="btn btn-default">Go</button>
                                    </form>
                                    <div className="nav navbar-form navbar-right">
                                        <div className="form-group">
                                            <button onClick={this.showTaskEditor} type="button" className="btn btn-default" aria-label="Left Align">
                                                <span className="glyphicon glyphicon-plus" aria-hidden="true"></span>
                                            </button>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </nav>
            );
    }
});

module.exports = SearchSection;
var React = require('react');
var Project = require('./Project.react');
var ProjectStore = require('../stores/ProjectStore');
var TaskEditor = require('./TaskEditor.react.js');
var MoustrapMixin = require('./MoustrapMixin');
var JustDoActions = require('../actions/JustDoActionCreator');

function getStateFromStores() {
    return{
        projects:ProjectStore.getAll(),
        showTaskEditor:ProjectStore.getTaskEditorVisibility()
    }
}


var ProjectSection = React.createClass({
    mixins: [MoustrapMixin],
    getInitialState: function(){
        return getStateFromStores();
    },

    componentDidMount: function() {
        this.bindShortcut('a', function () { JustDoActions.updateTaskEditorVisibility(true); });
        this.bindShortcut('esc', function () { JustDoActions.updateTaskEditorVisibility(false); });
        ProjectStore.addChangeListener(this._onChange);
    },

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

    render: function () {
        return (
                <div className="container-fluid">
                    <TaskEditor visible={this.state.showTaskEditor}/>
                    {this.state.projects.map(function(project){
                        return <Project key={project.id} project={project}/>;
                    })}                       
                </div>
            );
    },

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

module.exports = ProjectSection;

In the actions folder, there is the “JustDoActionCreator.js” file, which defines actions like “receiveAll” and “addTask.”

var JustDoAppDispatcher = require('../dispatcher/JustDoAppDispatcher');
var JustDoConstants = require('../constants/JustDoConstants');

var ActionTypes = JustDoConstants.ActionTypes;

module.exports = {
    receiveAll: function (projects) {
        JustDoAppDispatcher.dispatch({
            type: ActionTypes.RECEIVE_All,
            projects: projects
        });
    },
    updateTaskEditorVisibility: function (taskEditorVisibility) {
        JustDoAppDispatcher.dispatch({
            type: ActionTypes.SHOW_TASK_EDITOR,
            showTaskEditor: taskEditorVisibility
        });
    },
    addTask: function (task) {
        JustDoAppDispatcher.dispatch({
            type: ActionTypes.TASK_ADD,
            task: task
        });
    },

};

The Dispatcher is defined in the “JustDoAppDispatcher.js” file, and requires Flux.

var Dispatcher = require('flux').Dispatcher;

module.exports = new Dispatcher();

The Store is defined in the “ProjectStore.js” file, which defines all of the data fetching points, as well as one switch case to track actions. This emits a change event when the data is updated, as well as the React component listening to this store update itself.

var JustDoAppDispatcher = require('../dispatcher/JustDoAppDispatcher');
var JustDoConstants = require('../constants/JustDoConstants');
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
var ActionTypes = JustDoConstants.ActionTypes
var CHANGE_EVENT = 'change';
var _projects = [];
var _taskEditorVisiblility = false;

function setTaskEditorVisiblility(taskEditorVisiblility) {
    _taskEditorVisiblility = taskEditorVisiblility;
}
function addTask(task) {
    _projects[0].task.push(task);
}
var ProjectStore = assign({}, EventEmitter.prototype, {
    emitChange: function () {
        this.emit(CHANGE_EVENT);
    },

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

    removeChangeListener: function (callback) {
        this.removeListener(CHANGE_EVENT, callback);
    },
    getAll: function () {
        return _projects;
    },
    getTaskEditorVisibility: function () {
        return _taskEditorVisiblility;
    },
});
ProjectStore.dispatchToken = JustDoAppDispatcher.register(function (action) {
    switch (action.type) {
        case ActionTypes.RECEIVE_All:
            _projects = action.projects;
            ProjectStore.emitChange();
            break;
        case ActionTypes.SHOW_TASK_EDITOR:
            setTaskEditorVisiblility(action.showTaskEditor);
            ProjectStore.emitChange();
            break;
        case ActionTypes.TASK_ADD:
            addTask(task);
            ProjectStore.emitChange();
            break;
        default:
            //do nothing

    }
});

module.exports = ProjectStore;

There also a Gulp file, named “gulpfile.js,” which is used to define a set of classes. Here Browserify is tasked to do two activities: the first is to bundle the CSS and Javascript files, and the second one is to convert the activity from “JSX” into plain Javascript code. A watch is added here to rerun this process when any Javascript files change.

var gulp = require('gulp');
var source = require('vinyl-source-stream');
var browserify = require('browserify');
var reactify = require('reactify');

gulp.task('browserify', function () {
    browserify('./static/scripts/js/main.js')
      .transform('reactify')
      .bundle()
      .pipe(source('main.js'))
      .pipe(gulp.dest('./static/scripts/dist/js'));
});


gulp.task('default', ['browserify']);

gulp.task('watch', function () {
    gulp.watch('./static/scripts/js/**/*.*', ['default']);
});

Conclusion

This is just an overview of React with Flux, which also explains why this is quickly getting popular. We have provided steps to set up the development environment for Javascript-based (with or without React) web development. We have also given a code walk-through, which should help you understand how things get placed and how they work in React with Flux.