02. November 2015

Wiring up React and Backbone.js

Backbone is a piece of software I love very much. Compared to other behemoth like frameworks I admire the fact that it encourages me to do things right while thinking about them myself. And if I need answers I can just read its source code and get the answers that I need. It basically taught me development that goes further than $('#logo').magicPluginDust().


A modern view layer

If there is one thing in Backbone that feels outdated it’s probably its view layer. With amazing things like the Virtual DOM and React happening and in an incredibly advanced state, why not mix and match the established and precious parts of Backbone with the cool kids that rule the block nowadays?

Let’s build something

Ever wanted to know how many times you clicked that button? Let’s find it out!

MVC(V)

How to combine Backbone and React is pretty obvious. Backbone takes over the model part, React is in charge of the View layer and the Controller (ControllerView that is to be precise) is where the two of them meet.

The Model

// click-model.js
import {Model} from 'backbone';

export default Model.extend({
    defaults: {
        clicked: 0
    } 
});

The View

// view.js
import React, {createClass, PropTypes} from 'react';
import {Model} from 'backbone';

export default createClass({
    displayName: 'View',
    propTypes: {
        model: PropTypes.instanceOf(Model).isRequired
    },
    render(){
        return (
            <div>
                <button onClick={this.handleClick}>
                    Click me for fun and profit!
                </button>
                <span>
                    The button now has been clicked {this.props.model.get('clicked')} times. Amazing!
                </span>
            </div>
        );
    },
    handleClick(){
        const previousValue = this.props.model.get('clicked');
        this.props.model.set('clicked', previousValue + 1);
    } 
});

The Controller

// controller.js
import React, {createClass} from 'react';
import ClickModel from './click-model';

export default createClass({
    displayName: 'Controller',
    componentWillMount(){
        this.model = new ClickModel();
    },
    componentDidMount(){
        this.model.on('change', () => {
            this.forceUpdate();
        });
    },
    render(){
        return <View model={this.model} />
    }
})

The App

// app.js
import React from 'react';
import ReactDOM from 'react-dom';
import Controller from './controller';

ReactDOM.render(<HomeController />, document.querySelector('#mount-node'));

That’s it. The data flows nicely and unidirectional through your application and rerendering is completely controlled by the events that your model triggers. While amazing approaches like redux take over the frontend application world by storm, I think it’s always interesting to see how it can be done differently. You have an existing backbone app and want to leverage React? You probably don’t need a complete rewrite. You can keep the good parts.