Live data from Hacker News

Optimizing React Rendering

flexport.engineering

31–40 of 79 posts

Re: Optimizing React Rendering

#31
Pretty good post, minus the advice to always use PureComponent everywhere (per Ben's comment in this thread).

If anyone's interested, my React/Redux links list has a large section of other articles on various React-related performance concerns, including benchmarking and optimization approaches: https://github.com/markerikson/react-redux-links/blob/master... .

Re: Optimizing React Rendering

#32

> So all you have to do is use PureComponent everywhere and you’re good to go. There’s nothing more to it. Enjoy your new blazing fast React app! (I work on React.) This isn't quite right. If we recommended that PureComponent be used everywhere, it would probably be the default already. Rather -- the comparison to decide whether or not a component should be rerendered costs something, and in the case that you do want…

> If we recommended that PureComponent be used everywhere, it would probably be the default already. > Instead, we'd suggest you be conscious of where you need to do the comparisons. I'm not following, wouldn't that mean PureComponent by default and opt-in specialized checks when needed?

No, because PureComponent does have a check.

His point is that you don't always need that check - that check has overhead too!

Basically PureComponent is just a specialized case of shouldComponentUpdate so it's better practice to be mindful of where you're calling that anyhow.

It's also why there's the push to use stateless functions (when you can) because the kind of pseudo micro-optimization that PureComponent actually is can have counter-intuitive consequences.

Re: Optimizing React Rendering

#33

> So all you have to do is use PureComponent everywhere and you’re good to go. There’s nothing more to it. Enjoy your new blazing fast React app! (I work on React.) This isn't quite right. If we recommended that PureComponent be used everywhere, it would probably be the default already. Rather -- the comparison to decide whether or not a component should be rerendered costs something, and in the case that you do want…

Is it considered best practice to use the "key" of a child element to signify if it should rerender? This is what I've been doing and it seems to work well. If a parent updates its state, and then as a result, changes the props of some or all of its children, the parent sets the "key" of a child to effectively a hash of the props of that child.

I don't know the internal details but that sort of abuse of the key attribute seems like a dangerous thing to rely on.

I'll assume your key is quick to calculate. If a prop change causes the hash / key to change then react doesn't know how to reuse the dom fragment. I guess it will just reuse the stuff that's in the same location in that case so maybe it's fine. You'll lose the advantage that keys give you in the first case which is dealing with reordering.

And actually, just because the key changes or not, that doesn't cause a rerender or not. The rerender is always going to happen. Right? Unless I'm missing something.

Re: Optimizing React Rendering

#34

From the article: > Fixing the issue is pretty simple*. We simply need to short circuit the re-rendering for a subtree if we know that the subtree hasn’t changed. Not a frontend guy but I've seen this theme more than once on HN recently. It seems to me that addressing this anti-pattern would be built right in to modern React components. Isn't efficient DOM manipulation by pruning non-necessary changes kind of their t…

Efficient DOM manipulation is their thing.

But that sentence is talking about VirtualDOM rendering - which still takes time - not DOM manipulation.

Basically it's saying "if we don't need to do work, we shouldn't". Which React already does for DOM manipulation and this kind of optimization does it for virtualDOM creation.

Re: Optimizing React Rendering

#36
post #24

Earlier quoted context omitted.

You can partially apply the function where you know the parameter; i.e. assign onDelete to: this.handleDelete.bind(this, i)

The reason arrow functions and bind don't play well with PureComponents is that they return a new function instance each time. This means that the Data pure component will wastefully re-render even if none of the other props change.

Only if you did that in the render function.

If you did this.foo = this.foo.bind(this, props.bar) in the constructor then it would be the same function each time.

Re: Optimizing React Rendering

#37

> So all you have to do is use PureComponent everywhere and you’re good to go. There’s nothing more to it. Enjoy your new blazing fast React app! (I work on React.) This isn't quite right. If we recommended that PureComponent be used everywhere, it would probably be the default already. Rather -- the comparison to decide whether or not a component should be rerendered costs something, and in the case that you do want…

How do function(al?) components compare in performance to PureComponents?

e.g.,

    const MyComponent = props => (...);
vs

    class MyComponent extends PureComponent {...}

Re: Optimizing React Rendering

#38
post #25

Is there special logic in react that binds arguments of a function to the props with the same name? I'm talking about the handleDelete "fix" in the article: render() { const views = this .props.dataList.map((d, i) => { return }); } handleDelete(index) { //... } I guess they just call that function from within the Data component with the correct parameter. But then, Data component needs to know how to call that functi…

> I guess they just call that function from within the Data component with the correct parameter. Yep > Is there a better way? We're experimenting with some other options internally. Once we have a better sense of what works best, we will post another article on our learnings :)

Assuming your "deleteDataAt" function is a Redux action creator that dispatches an action to delete the list item -- if this is the case, then continue passing that action creator as a prop to the child, and since you've also passed down the index, the child can simply apply that action creator as the event listener. Eg. in the code snippet you've provided, I would have just done:

return ( );

Then your onClick in the child would be: onClick = (_e) => this.props.deleteDataAt(this.props.index);

Correct me if I'm missing anything!

Re: Optimizing React Rendering

#39
post #19

Is there special logic in react that binds arguments of a function to the props with the same name? I'm talking about the handleDelete "fix" in the article: render() { const views = this .props.dataList.map((d, i) => { return }); } handleDelete(index) { //... } I guess they just call that function from within the Data component with the correct parameter. But then, Data component needs to know how to call that functi…

By using the property initializer syntax [1] [2] [1] https://facebook.github.io/react/docs/handling-events.html [2] https://babeljs.io/docs/plugins/transform-class-properties/

That solves the problem of binding 'this', but doesn't solve the problem of supplying the index to the callback function. Essentially you have only two options for doing that.

One is to bind the callback function to a certain index in advance and then supply that callback to your child via props so it already knows the relevant index and doesn't need calling with any extra parameters. The trouble with this one is that it creates a new function every time, which is inefficient in itself and horrible if it winds up causing your child to rerender because props changed even though in practice you're passing an identical function every time.

The other is to supply a callback where the child component is responsible for supplying the extra index information when it calls the function, either by directly passing the index as a parameter or via an indirect route such as using data-* attributes as 'kentor mentioned. This is more efficient, but it creates tighter coupling between the child and parent components.

In practice, it seems most projects adopt the second strategy because the tighter coupling is usually much less of a problem in practice than the performance penalty, but neither solution is ideal. Unfortunately, JavaScript's semantics don't make it easy to have the equivalent of a "deep equal" comparison on functions that would return true for two copies of the same function with the same bound values.

Re: Optimizing React Rendering

#40
post #8

From the article: > Fixing the issue is pretty simple*. We simply need to short circuit the re-rendering for a subtree if we know that the subtree hasn’t changed. Not a frontend guy but I've seen this theme more than once on HN recently. It seems to me that addressing this anti-pattern would be built right in to modern React components. Isn't efficient DOM manipulation by pruning non-necessary changes kind of their t…

I think it is an anti-pattern that is a result of the language it's built on. This is one place where using Clojurescript wrappers of React has a real payoff - immutable datastructures make equality checking very very cheap.

A good patch for this is ImmutableJS
Post reply on HN