< Return to Blog

Event Driven React JS Components via an Event-Emitter Mixin

React is great in terms of its virtual DOM, and JSX makes the code so much more readable.

When leveraging React in terms of Rails, I highly recommend the reactjs/react-rails gem as this integrates it with the help of the asset pipeline, allowing one to setup components in app/assets/javascripts/components thanks to a components.js manifest file.

However, I wanted to be able to trigger components to re-render using an event system such as Backbone.Events, although for this quick example, I will be using EventEmitter.

$(function () {
    var globalEmitter = new EventEmitter();

    var triggerEmitter = function (payload) {
        console.log("Event payload %O", payload);
        globalEmitter.emit('change', payload);
    };

    var makeChangeEventMixin = function (emitter) {
        return {
            componentDidMount: function () {
                emitter.addListener('change', this.__makeChangeEventMixin_handler_);
            },
            componentWillUnmount: function () {
                emitter.removeListener('change', this.__makeChangeEventMixin_handler_);
            },
            __makeChangeEventMixin_handler_: function (payload) {
                console.log('__makeChangeEventMixin_handler_ fired with payload=%O', payload);
                this.replaceState(payload);
            }
        };
    };

    var UIComponent = React.createClass({
        mixins: [makeChangeEventMixin(globalEmitter)],
        getInitialState: function () {
            return {
                data: {
                    name: ''
                }
            };
        },
        render: function () {
            var data = this.state.data;

            console.log('Data: %O', data);
            return React.DOM.div(null,
            React.DOM.span(null, "Hi there '" + data.name + "'"))
        }
    });

    React.render(
    React.createElement(UIComponent),
    document.getElementById('example'));

    $('#trigger--button').on('click', function (e) {
        e.preventDefault();
        triggerEmitter({
            data: {
                name: "Mike"
            }
        })
    });
});

The above contrived example (Fiddle) renders a component on screen and the button's click event triggers a re-render of the component, passing along the payload data.

Typically, React goes hand-in-hand with Flux, which aids in establishing a predictable data layer. I hope to get into Flux at some point, but for this rather simplistic use-case, I'm rather happy with this event-driven approach.