Once we started using React in our projects, our productivity went up. We were able to deliver complex view with many moving parts in a fraction of a time we would need before with other technologies.

Our application grew with time and some of our applications got really complex views. In some point, it was really inconvenient to pass down some common data in large component trees. It wasn’t a no-go, but a bit tiring.

The problem

Let’s see this view with crazy-nested structure in one of our projects. There were a lot of actions that could be triggered from that view – you could inline-edit the names of all elements, click a button to pop-up a modal with another application.

All of the actions on the view above were triggered using the eventing system. So if I wanted to edit the name of a threat, I had to fire an event to inform appropriate app about that:

this.props.eventBus.publish('threatNameEdited', newName);

We were passing the eventBus with the props. You could imagine how inconvenient it was to pass this object through at least 4-levels deep components tree.

Contexts for the rescue

Starting from version 0.12, React.js developers added the contexts feature into a codebase. It basically lets you to pass some data through all nodes in components tree.

You need to remember that this feature is still in development and its API may change in next version of React.

Context is something that works similarly as properties and state. But, instead of explaining it in long sentences, let’s see the example.

Quick Example

We defined 2 components: parent and its child.

React.createClass({
  displayName: 'Parent',

  render: function() {
    return <Child />;
  }
});

React.createClass({
  displayName: 'Child',

  render: function() {
    return <div>Yo!</div>;
  }
});

Let’s say, we want to propagate eventBus down the components tree, with root in Parent.

The root of the context must define how the context looks like and what type each element in it has. In our case, Parent is a root.

It’s also worth noting that the component which created the context, cannot access it directly.

React.createClass({
  displayName: 'Parent',

  // Define how the context looks like
  getChildContext: function() {
    return {
      eventBus: this.props.eventBus
    }
  }

  // Define types of elements in context
  // We define it the same way as `propTypes`
  childContextTypes: {
    eventBus: React.PropTypes.object.isRequired
  },

  render: function() {
    return <Child />;
  }
});

The components below the root don’t get the access to a context automatically. They must specify what items from contexts they are interested in.

React.createClass({
  displayName: 'Child',

  // That's the only thing you need to add
  contextTypes: {
    eventBus: React.PropTypes.object.isRequried
  },

  render: function() {
    return <div>Yo!</div>;
  }
});

And from now on, you can access the eventBus from a Child component using this.context.eventBus.

What’s more, you can access context from lifecycle methods like componentWillUpdate, shouldComponentUpdate and so on. Context is usually passed as the last argument.

When not to use contexts?

Contexts aren’t the best way pass domain related models. They couple your code and make it less reusable. The readability of the code may also hurt.

Have in mind what I mentioned before - contexts feature is still under development. React developers don’t guarantee that the behaviour and API will stay the same. You should try to isolate parts of your systems using contexts.

When to use contexts?

If you look at the data that is shared between most of your components, you may find some elements that are commonly used. Here are some examples from projects I worked on:

  • Current user model
  • Eventing bus
  • Store in Flux library
  • Session storage (theme or language settings)

More

For more information, I recommend checking out the official React docs. They are the great written and reliable source of information.

If you’re interested in checking out event-bus I mentioned in the article, check out our NPM package and its GitHub repository. It a lightweight package with powerful possibilities. And it has absolutely no dependencies!

comments powered by Disqus