LoginSignup
3
3

More than 5 years have passed since last update.

Modern React Flux application example (pt. 4)

Last updated at Posted at 2014-10-29

Continuing from where we left off in part 3, I want to talk about profiling performance for sufficiently large views.

Retraction

I made a silly typo with mixin instead of mixins, causing my Pure Render Mixin to not be incorporated into my component. The original should work fine in most cases and there is no need to create your own propEquals. Let this be a lesson to me to avoid programming at 1AM... (I put in a PR for this here. Let's see if it's worthy of being merged.)

An issue with the original PureRenderMixin...

"But hold up, what about components that get recomputed, like the rows in our table? What happens with those? The member properties' refs will be the same, sure, but the props objects themselves will be new objects each time. Why are you telling me to use Pure Render Mixin if it isn't even going to work!?"

We need to actually inspect the source of the pure render mixin and study some JS to determine if this even does what we want (don't worry, we'll just do trial and error to make our point).

Remember that PureRenderMixin takes our props and state and calls shallowEqual on them:

// excerpt from ReactComponentWithPureRenderMixin...
shouldComponentUpdate: function(nextProps, nextState) {
  return !shallowEqual(this.props, nextProps) ||
          !shallowEqual(this.state, nextState);
}

and shallowEqual is defined as such:

function shallowEqual(objA, objB) {
  if (objA === objB) {
    return true;
  }
  var key;
  // Test for A's keys different from B.
  for (key in objA) {
    if (objA.hasOwnProperty(key) &&
        (!objB.hasOwnProperty(key) || objA[key] !== objB[key])) {
      return false;
    }
  }
  // Test for B's keys missing from A.
  for (key in objB) {
    if (objB.hasOwnProperty(key) && !objA.hasOwnProperty(key)) {
      return false;
    }
  }
  return true;
}

So this works for components that aren't recomputed or hold on to the same property refs, but the problem becomes quite clear when we do some simple tests:

var myArray = [1,2,3,4]
// undefined
var myNumber = 1234
// undefined
var a = { a: myArray, b: myNumber }
// undefined
var b = { a: myArray, b: myNumber }
// undefined
a === b
// false
a.a === b.a
// true
a.b === b.b
// true

Of course a and b aren't going to be equal, since they are two separate objects. Sure, their properties point to the same references, but this isn't going to work with shallowEqual. For this purpose, I have my own function propsEqual, which I use to compare properties of two objects. Quite literally, shallowEqual without the top level check.

// from propsEqual.js
module.exports = function (objA, objB) {
  var key;
  // Test for A's keys different from B.
  for (key in objA) {
    if (objA.hasOwnProperty(key) &&
        (!objB.hasOwnProperty(key) || objA[key] !== objB[key])) {
      return false;
    }
  }
  // Test for B'a keys missing from A.
  for (key in objB) {
    if (objB.hasOwnProperty(key) && !objA.hasOwnProperty(key)) {
      return false;
    }
  }
  return true;
}

Profiling performance

Not much to really say here other than to stress the importance of using tools like the Timeline tool in Chrome. Let's see what our performance was when we used the Pure Render Mixin didn't use anything (i.e. with our computed elements):

kobito.1414558053.529165.png

We were only adding 100 lines and it took 1.4 seconds? Ouch. Now with propsEqual:

kobito.1414557979.203442.png

Much better. Remember this is adding 100 rows directly. What about a single row when we have lots of elements?

kobito.1414558245.908874.png

vs

kobito.1414558304.451006.png

Hope you're getting the picture here. By informing React on how to optionally render the components and properly dealing with references for propsEqual/shallowEqual, we're able to improve performance dramatically.

Closing

I hope any part of this series of articles was useful to someone. If anything, this helps me by saving me from saying the same things over and over again.

Please inform me of any mistakes made through e-mail, twitter, or comments here.

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3