Memoized function binding in React
A common problem in react development is unnecessary virtual DOM re-rendering caused by bound functions. Consider the following example:
When the value of Textbox changes, all five of the Option components will re-render even though their data is exactly the same. We can’t prevent this with a strict equality check in shouldComponentUpdate because every time we bind the function we are creating a new function with a different reference.
We could instead pass in the unbound function and the value we wish to bind so the Options component could do it internally. However this is unsatisfactory because it makes Option more closely coupled to the ApplicationForm component.
A better solution is memoization. The first time we bind an argument to a function its reference is cached, then if we try to do the same thing again we just get the same reference back. With a memoized binding function we could write the ApplicationForm component like this:
It looks almost identical, but the Option component can now implement shouldComponentUpdate logic to prevent unnecessary re-renders.
So let’s try writing this memoized binding function…
This looks like it might work. The first time we bind “title” to setValue the checkCache function will return false and we add the newly bound function to the cache. The next time we try to do the same we’ll just get the cached version back.
But there’s a problem. Think about what happens when we go on to bind “name” to setValue. Our old cache will be wiped out so our Options will still be re-rendered.
What we need is a cache with a deeper history. We can use ES6 Maps to help out because they let us use functions as keys!
Our cache is now a multidimensional map. First we look up the function and get a map back. On this second map we look up the argument and get the bound function.
So now you know how to write a memoized binding function, but if you just want to get binding you can install pure-bind from npm.
npm install pure-bind --save
It is similar to the last example, but takes multiple arguments instead of just one.