Streamlined React Components

A React component’s render should be a pure function of its props. Pass in the same props and you should always get back the same results. You can then streamline the component with a shouldComponentUpdate function that bypasses rendering when the props haven’t changed. This optimisation technique works smoothly, except when it comes to Hyperlinks. Hyperlinks have a nasty habit of forcing props into components, making them update when they shouldn’t have to. In this post, I’ll show how to tame your Hyperlinks using a new declarative approach to routing.

Let’s start with an example of a list of items that can be sorted and filtered. It’s made up of three components: Sort, Filter and List. If we use Buttons, rather than Hyperlinks, to implement the sorting and filtering functionality, then here’s the props each component needs:

  • Sort component needs the sort prop to determine the new sort order.
  • Filter component needs the filter prop to style the currently active filter.
  • List component needs the sort, filter and items props to display the list

Components coloured by props when Buttons used

If we imagine that the filter prop is blue and the sort prop yellow, we can draw a picture of the example and colour in the components to match their props. The Sort component is yellow because it needs the sort prop, the Filter’s blue to match the filter prop and the List is green because it expects both yellow and blue props.

Any component that isn’t green can be streamlined with a shouldComponentUpdate function. The green List component can’t be streamlined because it has to update when either the filter or the sort changes. The yellow Sort component, on the other hand, only has to update when the sort changes:

shouldComponentUpdate(oldProps, props) {
  return oldProps.sort !== props.sort;
}

However, all the components turn green if we implement the sorting and filtering using Hyperlinks instead of Buttons. The key difference between a Hyperlink and a Button is that a Hyperlink has an href attribute. To populate an href we need both the filter and the sort. For example, the Sort component needs the filter prop as well as the sort prop so it can build a URL that holds the current filter along with the new sort order.
Components coloured by props when Hyperlinks used
You can see how Hyperlinks force props into your components. They force the filter prop into the Sort component and the sort prop into the Filter component. These extra props turn the Sort and Filter components green. Green components can’t be streamlined with shouldComponentUpdate functions because they always have to update. But, we can turn the Sort back to yellow and the Filter back to blue by using a declarative approach to routing.

Declarative Routing

The Navigation router introduces a declarative way to build Hyperlinks. We’ll use it to remove the filter prop from the Sort component and the sort prop from the Filter component, turning them back to yellow and blue respectively. First, let’s see what the sorting Hyperlink looks like built using a traditional imperative router like the React Router:

var data = {
  sort: this.props.sort === 'up' ? 'down' : 'up',
  filter: this.props.filter
};
<Link to={`${data.filter}/${data.sort}`} />

You can see that the React Router expects us to pass the URL to the Link component. With this imperative approach, there’s no way to turn the Sort component yellow because we can’t build the URL without the filter prop. Compare this to the equivalent sorting Hyperlink built using the RefreshLink component from the Navigation router:

<RefreshLink
  navigationData={{
    sort: this.props.sort === 'up' ? 'down' : 'up',
    filter: this.props.filter
  }} />

This code is much more declarative. Instead of building the URL ourselves, we’re telling the RefreshLink what data we want in the href and letting it build the URL for us. But, the Sort component is still green. To remove the filter prop and turn the Sort component yellow, we can get the RefreshLink component to keep track of the current data rather than pass the filter in:

<RefreshLink
  navigationData={{sort: this.props.sort === 'up' ? 'down' : 'up'}}
  includeCurrentData={true} />

This code is even more declarative. We specify that the href should include the current filter value without deciding how and when to get it. Without the filter prop, the yellow Sort component can be streamlined with a shouldComponentUpdate function that prevents it from updating unless the sort prop changes. This doesn’t stop the latest filter making it into the href because the RefreshLink auto updates whenever the current data changes.

We can apply these declarative techniques to the filter Hyperlinks to turn the Filter component back to blue. If we also declaratively style the active filter Hyperlink, then we can turn the Filter component white so that it never has to update. You can see the yellow Sort and white Filter components in action in this JsFiddle of the complete example.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s