How to create a Data Container Component in React

One pattern I’ve used quite a lot while working with React at the BBC and Discovery Channel is the Data Container pattern. It became popular in the last couple of years thanks to libraries like Redux and Komposer.

wireframe

The idea is simple. When you build UI components in React you feed data into them via containers. Inside those containers you may need to access different data sources, filter data, handle errors, etc. So data containers help you build data-driven components and separate them into two categories: Data components and Presentational components.

  • A Presentational component is mainly concerned with the view, it doesn’t specify how the data is loaded or mutated. They receive data and callbacks exclusively via props.
  • A Data component talks to the data sources and provides the data and behaviour to the Presentational component. It’s usually generated using higher order function, such as connect() or createContainer().

There are actually 2 ways to implement this pattern, using inheritance or composition:

  1. Inheritance: a React component class extends a Data Container component class.
  2. Composition: a React component is injected into the Data Container (React Komposer uses this approach).

I recommend composition over inheritance as a design principle because it gives you more flexibility.

Code Example

Lets say you want to display a list of notifications and you have 2 components:
NotificationsContainer and NotificationsList

First you need to fetch the data and add it to the NotificationsContainer:

import React, {createElement} from 'react';
import PropTypes from 'prop-types';
import https from 'https';
import DataStore from '/path/to/DataStore';

export default function createContainer(SubComponent, subComponentProps) {

    class DataContainer extends React.Component {

        constructor(props) {
            super(props);

            this.name = props.name;
            this.dataSourceUrl = props.dataSourceUrl;
            
            this.state = {
                data: null,
                error: null
            };
        }

        componentDidMount() {
            this.setInitialData();
        }

        setInitialData() {
            if (DataStore.hasData(this.name)) {
                this.setState({
                    data: DataStore.getData(this.name)
                });
            } else {
                this.fetchData();
            }
        }

        fetchData() {
            https.get(this.dataSourceUrl, res => {
                let chunkedData = '';

                res.on('data', data => {
                    chunkedData += data;
                });

                res.on('end', () => {
                    this.setState({
                        data: chunkedData
                    });
                });

                res.on('error', (error) => {
                    this.setState({error});
                });
            });
        }

        render() {
            return createElement(
                SubComponent,
                Object.assign({}, subComponentProps, this.state)
            );
        }
    }

    DataContainer.propTypes = {
        name: PropTypes.string,
        dataSourceUrl: PropTypes.string
    };

    return DataContainer;
}

Then you need to create a NotificationsList component that receives the data as a prop:

import React from 'react';
import PropTypes from 'prop-types';

class NotificationsList extends React.Component {

    constructor(props) {
        super(props);
    }

    render() {
        const listItems = this.props.data.items || [];

        return (
            <ul>
                {listItems.map((item, index) => {
                    return <NotificationListItem item={item} index={index} />;
                })}
            </ul>
        );
    }
}

NotificationsList.propTypes = {
    data: PropTypes.object,
    error: PropTypes.object
};

export default NotificationsList;

And, finally, you need to create and render the data container:

import React from 'react';
import NotificationsList from './NotificationsList';
import createContainer from './createContainer';

export default class HomePage extends React.Component {

    render() {
        const NotificationsContainer = createContainer(
            NotificationsList, {
                propName: 'propValue'
            }
        );

        return (
            <NotificationsContainer 
                dataSourceUrl="/api/notifications/list" 
                name="notifications" />
        );
    }
}

If you are looking for something a bit more advanced, similar to what I was using at the BBC, then check out this nice little project called  Second. Or, if you are building a more complex app and need to manage state or map components to multiple containers, then you should consider using Redux. Here’s a great presentation about React/Redux.

For those using React 16.3, keep an eye on the following projects: react-waterfall and unistore. They are data stores built on top of the new Context API.

If you don’t want to miss any of my articles, follow me on twitter @fedecarg

Website performance monitoring tool

Monitoring systems allow you to monitor changes to your front-end code base over time, catching any regression issues and monitoring the ongoing effects of any performance optimisation changes. Easy to use dashboards are a must when it comes to monitoring the state of your web apps. Companies like Calibre or SpeedCurve offer this as a professional service, but not everyone can afford them.

Meet SpeedTracker

SpeedTracker is an open source (MIT license) self-hosted solution to monitor your app’s uptime and APIs, developed by Eduardo Bouças. It runs on top of WebPageTest and makes periodic performance tests on your website and shows a visualisation of how the various performance metrics evolve over time.

SpeedTracker provides clean charts and graphs that can help you identify possible problem areas.

speedtracker01

Check out the demo here: https://bbc.github.io/iplayer-web-speedtracker/

WebPageTest is an incredibly useful resource for any web developer, but the information it provides becomes much more powerful when monitored regularly, rather than at isolated events. Web application monitoring is not just for detecting downtime, it also gives you additional insight into performance trends during peak load times, as well as by time of day, and day of the week.

speedtracker04

For me, the best thing about SpeedTracker is that it runs on your GitHub repository! Data from WebPageTest is pushed to a GitHub repository. It can be served from GitHub Pages, from a private or public repository, with HTTPS baked in for free.

SpeedTracker also allows you to define performance budgets for any metric you want to monitor and receive alerts when a budget is overrun. This can be an e-mail or a message on Slack.

For instructions on how to install this tool, visit the following GitHub repo: https://github.com/speedtracker/speedtracker

 

Node.js: How to mock the imports of an ES6 module

The package mock-require is useful if you want to mock require statements in Node.js. It has a simple API that allows you to mock anything, from a single exported function to a standard library. Here’s an example:

app/config.js

function init() {
    // ...
}

module.exports = init;

app/services/content.js

import config from '../../config.js';

function load() {
    // ...
}

module.exports = load;

test/services/content_spec.js

import {assert} from 'chai';
import sinon from 'sinon';
import mockRequire from 'mock-require';

describe('My module', () => {

    let module; // module under test
    let configMock;

    beforeEach(() => {
        configMock = {
            init: sinon.stub().returns("foo")
        };

        // mock es6 import (tip: use the same import path)
        mockRequire("../../config.js", configMock);

        // require es6 module
        module = require("../../../app/services/content.js");
    });

    afterEach(() => {
        // remove all registered mocks
        mockRequire.stopAll();
    });

    describe('Initialisation', () => {

        it('should have an load function', () => {
            assert.isFunction(module.load);
        });

    });

});

Intercepting class method invocations using metaclass programming in Python

In Ruby, objects have a handy method called method_missing which allows one to handle method calls for methods that have not been defined. Most examples out there explain how to implement this in Python using __getattr__, however, none of them (honestly, none) explain how to intercept class method (@classmethod) invocations using __metaclass__.

And that’s why I wrote this post.

The function type is the built-in metaclass Python uses, it not only lets you know the type of an object, but also create classes on the fly. When you write, for example: class Example(object) the class object Example is not created in memory straight away. Python looks for the __metaclass__ attribute in the class definition and if it finds it, it uses it to create the object class Example. If it doesn’t, it uses type to create the class. The main purpose of a metaclass is to change the class automatically, when it’s created.

Here’s an example of how to use metaclass programming to intercept class method calls similar to the method_missing technique in Ruby:

class ClassMethodInterceptor(type):

    def __getattr__(cls, name):
        return lambda *args, **kwargs: \
                   cls.static_method_missing(name, *args, **kwargs)

    def static_method_missing(cls, method_name, *args, **kwargs):
        e = "type object 'static.%s' has no attribute '%s'" \
            % (cls.__name__, method_name)
        raise AttributeError(e)

class Example(object):

    __metaclass__ = ClassMethodInterceptor

    def __getattr__(self, name):
        return lambda *args, **kwargs: \
                   self.method_missing(name, *args, **kwargs)

    def method_missing(self, method_name, *args, **kwargs):
        e = "type object '%s' has no attribute '%s'" \
            % (self.__class__.__name__, method_name)
        raise AttributeError(e)

    @classmethod
    def static(cls):
        print 'static.%s' % cls.__name__

    def instance(self):
        print self.__class__.__name__

Console:

>>> Example.static()
static.Example
>>> Example.foo()
Traceback (most recent call last):
...
  File "example.py", line 12, in static_method_missing
    raise AttributeError(e)
AttributeError: type object 'static.Example' has no attribute 'foo'
>>> e = Example()
>>> e.instance()
Example
>>> e.foo()
Traceback (most recent call last):
...
  File "example.py", line 26, in method_missing
    raise AttributeError(e)

AttributeError: type object 'Example' has no attribute 'foo'

If you ever implement something like this, remember that Python doesn’t distinguish between methods and attributes the way Ruby does. There is no difference in Python between properties and methods. A method is just a property whose type is instancemethod.

API Development Tips

Organisations who are paying attention already know they need to have an open web API, and many already have under development or in the wild. Make sure you haven’t been caught by the pitfalls of many early API releases.

Multiple points of failure

  • Back-end systems: db servers/caches, hardware failures, etc.
  • Interconnections: router failures, bad cables, etc.
  • External Dependencies: fail whales, random cloud latency, etc.

The 5 tips

  1. Test it all
    • Unit test are not enough, they are just the beginning.
    • Test what users experience. Perform end-to-end black box tests.
    • Replay your access logs. Very accurate.
    • Validate return payloads. A stack trace is not valid XML.
  2. Plan for future versions
    • Versions are not sexy/semantic (but do it anyway).
    • Announce versions often.
  3. Embrace standards
    • APIs are better when predictable.
    • Standard approaches mean tools.
    • Avoid uncomfortable migrations. No one wants an OAuthpocalypse.
  4. Monitor everything & be honest
    • Trends are your friend.
    • Users are not your early-warning ops team.
    • Be open and honest, or your users will tweet that your API sucks!
  5. Fail well
    • Well-formed errors win friends and makes users more tolerant to failure.
    • Make monitoring easy.
    • Don’t punish everyone. Determine who gets hurt most by failures.

Watch the video here: Understanding API Activity by Clay Loveless

Go is gaining momentum

Golang MascotThe Go language is gaining momentum among software engineers and PaaS/IaaS vendors. I think they all see potential in a simple, reliable, efficient and native-compiling language with a solid baseline API.

Thanks to its simplicity, performance, intuitive design and Google’s commitment to its future, Go could spark a change in the industry like we haven’t seen since the rise of Ruby in 2004. Ruby gained popularity among web developers and system administrators after David Hansson created Rails and Luke Kanies Puppet. Python, on the other hand, is still more attractive to teachers and academics and seems to be the preferred teaching language in many top universities, along with C/C++ and Java.

Go is more of an evolutionary than revolutionary language, and a great alternative to languages like Ruby, Python and C/C++, or platforms like Node.js. Experts predict that Go will become the dominant language for systems work in IaaS, Orchestration, and PaaS in the next couple of years. It has the potential to make a significant impact on server-side software, however, it still needs more adoption outside Google.

http://tour.golang.org/

Installing multiple versions of Ruby using RVM

Ruby Version Manager (RVM) is a tool that allows you to install multiple versions of Ruby and have multiple versions of the same interpreter. Very handy for those who have to maintain different applications using different versions of Ruby.

To start, download RVM and install the latest stable version of Ruby:

$ echo insecure >> ~/.curlrc
$ curl -L https://get.rvm.io | bash -s stable --ruby
$ source ~/.bash_profile

Install an old version of Ruby:

$ rvm install 1.8.6
$ rvm use 1.8.6 --default
$ ruby -v
ruby 1.8.6

Create a Gem set and install an old version of Rails:

$ rvm gemset create rails123
$ gem install rails -v 1.2.3
$ rails -v
Rails 1.2.3

Switch back to your system:

$ rvm system
$ rails -v
Rails 2.3.5

Switch back to your RVM environment:

$ rvm 1.8.6@rails123

And, if you want to remove Rails 1.2.3, just delete the Gem set:

$ rvm gemset delete rails123

Alternatively to RVM, you also might look into rbenv.