Icelab

Thinking and Learning React.js

We recently used Facebook’s React.js to build a mobile-focussed app for one of our clients. Getting a handle on how to build a React.js app with a bit of complexity was a great learning experience for us, so I thought I’d share some of the interesting aspects of it.

Routing

There are a few different options out there for building the routing in a React.js app, we used the routing that is part of Backbone.js to build out the structure. We define the routes in an object and map them to functions:

var Router = Backbone.Router.extend({
  "locations/:latLng/features/:type/:subtype":  "locationSubtype",
},
locationSubtype: function(latLng, type, subtype) {
  //render the correct React components here, passing in properties
  //the function arguments contain the values from the route.
});

The routing has an initialize function which renders the top level <Layout> component and attaches to the instance of the router. It also handles a few other housekeeping things, like responding to certain AppDispatcher and window events.

If you’re looking at routing options, there’s a new routing component for React on the block that appears to be quite fully featured and documented: React Nested Router. We’re definitely going to check it out for our next React app.

AppDispatcher

We’re creating an AppDispatcher by extending the Backbone.js Events and exposing some of our own functions on it. The AppDispatcher’s responsibilities are to keep track of event subscriptions and dispatch incoming events to all the subscribers of that event.

We use the AppDispatcher to notify when things happen and respond to them, for example:

// Whenever the user requests (and receives a successful geolocation)
AppDispatcher.on("geolocator:success", function(lng, lat) {
 //do something
});

And we trigger the event in a React component like this:

var onGetCurrentPositionSuccess = function(position) {
AppDispatcher.trigger("geolocator:success", position.lng, position.lat);
};

Within React components, you can set up listening for events in the componentWillMount function:

componentWillMount: function() {
AppDispatcher.on("geolocator:success", this._onGeolocatorSuccess);
},
_onGeolocatorSuccess: function(lng, lat) {
this._setMarker(
  new google.maps.LatLng(lat, lng)
);
}

You also need to unbind the events in the componentWillUnMount:

componentWillUnmount: function() {
AppDispatcher.off("geolocator:success", this._onGeolocatorSuccess);
}

TouchPreview React Component

Max built a reusable React component called TouchPreview to add additional classes to a component so that you can control its touch state styles. It’s things like this which make an app feel responsive and fast and nice, even though it’s just styling. Check it out here: https://gist.github.com/makenosound/ace158cf3e9f070e59d7

AnimationItem React Component

Another React component which Max built to make nice smooth transitions on large nested lists which may be re-rendered while they’re animated. In the AnimationItem component we have to do multiple requestAnimationFrame calls to make sure that the browser has rendered class attributes further up the tree that we’re relying on. In this app we add a little .direction--up or .direction--down class to the layout block to signify if you’re moving up or down the perceived navigation stack as well. See it here: http://codepen.io/makenosound/pen/rstvx

The React way

One theme that is coming up in a lot of our React projects is that React requires a different way of thinking about how you construct interfaces. Because of the way it continuously renders your HTML it gives you a lot of power to be able to know exactly what your interface is doing at any given time. So you need to build your components with that idea in mind otherwise you’ll end up fighting React a little.

Work with us, we’re good peopleGet in touch