React Advice for Faster Rendering

This is some advice that I’ve discovered through working on various React projects. Some of these practices are in response to issues with these projects. They are not intended to be a standard, but more of a guide – mainly for myself.

Don’t use componentWillReceiveProps

componentWillReceiveProps will be removed in React 17. It’s also often abused as some developers use it to set state.

Don’t set state in componentWillReceiveProps

Within the the lifecycle method order of React, componentWillReceiveProps comes before shouldComponentUpdate. If someone tried to set the state within componentWillReceiveProps then the shouldComponentUpdate function would fire once again. If the component didn’t use shouldComponentUpdate (because it’s not always necessary), then the render function would fire twice.

Use shouldComponentUpdate sparingly, but intelligently

React already performs a props and state comparison before running the render function, but it does so with a deepEquals test. What this means is that React is super fast with simple primitive props, such as strings, numbers, and booleans, but it can become slow with large objects.

There are several ways to speed up the default render check, but if you’re unable to make large structural changes in the codebase, then the simplest method is adding a shouldComponentUpdate and manually testing the props.

For some objects, it’s not a simple matter of testing if nextProp.myProp === this.prop.myProp, because the references might have changed even though the data is the same, so instead try JSON.stringify(nextProp.myProp) === JSON.stringify(this.prop.myProp). This comes with additional downsides, but is often faster than a full re-render.

Don’t use shouldComponentUpdate, use Containers

Wrapping a component in a container is a great was to directly access the datastore without requiring props to be passed by parent components. Instead of a waterfall of props, where the parent component needs to predetermine all of the props a child component would ever need, and passing them through a large list of JSX attributes, you can use the container to directly access the necessary information and reduce the amount of “knowledge” your parent components require.

Use selectors from reselect

Instead of adding data mutators within your component, or mutating your data when you retrieve it from the server creating duplicate data in the datastore, it’s easier to create a selector that will mutate the data for any component that wants to use it. In essence a selector could be a filter, or a way to change the datastore from one structure to a different one. Instead of an object of keys, maybe you need an array of entries.

Imagine the datastore holds an object referencing articles.

{
  "data": {
    "articles": {
      "abc": { ... },
      "def": { ... },
      "ghi": { ... }
    }
  }
}

Now, what if you need an array of articles for a list? Some people would pre-populate the datastore with the array once the AJAX service call is completed.

{
  "data": {
    "articles": {
      "abc": { ... },
      "def": { ... },
      "ghi": { ... }
    },
    "articlesArray": [{ ... }, { ... }, { ... }]
  }
}

This effectively doubles your datastore size and isn’t very efficient.

The other approach might be to add a filter in your components. This is another bad practice because if you add a filter to your component, maybe in the componentDidUpdate function, then the code could be duplicated in another component, adding to testability issues and code duplication.

The better approach is to create a selector which uses the data from the datastore to return the data in the format you require, in this case an array. Perhaps in another case you would need it sorted. You can always add options to the selectors to cover multiple cases.

Use Immutable.js

Immutable.js works by storing your data in the datastore as a class instead of a raw object. Some people find this frustrating because it’s more difficult to debug your data, but if you know about toJS() then this argument goes away.

Immutable also copies your data as properties of the component, so React can now use reference equality rather than deepEquals. A change to the data will only fire the render function once.

Use more basic props

Instead of passing an object or array, instead try passing a simpler ID or string-based property (could be a string or number for example). This way React’s default testing method doesn’t need to perform a deepEquals.

This last bit of advice builds upon using Containers, Selectors, and Immutable.js. Instead of passing large objects you can now use a container to use the simple ID in a selector to retrieve the immutable object from the datastore.

Changing car colors with ImageMagick

I was asked by a colleague if it’s possible to replace the color of a stock car image with a different color using an automated script. I found that ImageMagick has the ability to replace black and white with different colors using the +level-colors filter, but it’s a dumb find-replace method which replaces all instances of white with red. You can see with the image below that it’s just not perfect.

Read More

My experience with Angular 4 and server-side rendering using platform-server

Let me first state that I’m a professional Angular 1.x developer. I know Angular inside and out, and have fully grasped many of the complexities within Angular’s framework. However, I have little to no experience with Angular 2+, so I decided to try the latest Angular 4 code with robwormald’s ng-universal demo. The intent was to create a simple website with server-side rendering and a couple of minor AJAX service requests.

Read More

Making Brother Scanner Drivers work with Ubuntu 16.10

I have a Brother HL-2280DW network printer which is also a scanner, as many printers are nowadays. Brother, to their benefit, has decent Linux drivers and the printers are great for their reliability. The problem people have recently had, from around the Ubuntu 16.04 release is that the scanner drivers no longer work for some people. Hopefully this article can help guide people to the right solution.

Read More

Similarities between Angular 2+ objects and Angular 1 objects

This article will attempt to draw similarities between the various Angular scaffold types in regards to Angular 1 and Angular 2+ (known as AngularJS). The sections will be separated by Angular 2+ scaffold types, while the similar Angular 1 types will be described within each section.

Read More

Testing AngularJS Templates, Directives, Controllers, Services, Factories, and Filters

Angular is a framework that offers impressive testing ability through unit tests and template-based testing, which we will consider template-based unit testing.

Read More

Common Jasmine Matchers for AngularJS

Below are some useful matchers for AngularJS testing. Add them to a file called “matchers.js” and be sure to add that file to your test runner.

Read More