Hacker Newsnew | past | comments | ask | show | jobs | submit | dounan's commentslogin

That's a great point, and being aware of the dangers of shouldComponentUpdate is what this post is all about. There are a lot of gotchas when using PureComponents, and can lead to bugs if you're not careful.

Also, recalculating derived data (building static lists) in render() is very wasteful, and is also another gotcha when using PureComponents (object copying). Removing object copying from render() speeds up the actual render() call and allows you to take full advantage of PureComponents.

We are experimenting with ways to make all of this a bit easier, and hopefully will have some good news to share in Part 2 :)


I've updated the post to say 'in the right places' instead of 'everywhere' until we get some profiling data.


In our experience, React is not necessarily 'slow' by default. Re-constructing parts of the element tree each time can be a bit wasteful, but it is only as slow as your render() methods, and that is outside of React's control.

We have survived over 3 years with a massive application (over 2000 modules) and tons of wasteful re-rendering, but have only now started to notice any sluggishness. That makes React pretty fast in my mind.

Having said all that, we are experimenting with an 'all PureComponents' approach to potentially make React, but whether that turns out to be a good idea is yet to be seen (object comparisons in sCU are not free).


First off, thanks for your work on React! Makes all of our lives easier as developers :)

As dmnd pointed out, I'm not entirely convinced that dropping PureComponent everywhere is not a good idea.

For our app specifically, we unfortunately do data loading in a lot of places, which means that there are quite a bit more than just few places that can benefit from being a PureComponent. Our current idea is to try to make everything a PureComponent, and go back and 'unpurify' the places that have wasteful sCU comparisons. This might not turn out to be a good idea though, for the reasons you mentioned.

I'll make sure to do some profiling in our codebase once we get to that point, and see how much wasted sCU we are doing.


Atom editor with the 'One Dark' theme


nit: new component instance (not element)


I think we're both right- I believe it will create a new element and a new DOM element, rather than mutating the existing ones.


You're right. I misinterpreted your first comment to refer be referring to React elements, which is quite different from DOM elements https://facebook.github.io/react/blog/2015/12/18/react-compo...


> 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 ( <Data value={d} index={i} deleteDataAt={deleteDataAt} /> );

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

Correct me if I'm missing anything!


> Correct me if I'm missing anything!

You're not missing anything :) That approach also works. The important point is that you have to pass the extra index prop down to the child to avoid the bind in render.


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.


For this specific example you don't have access to the list index in the constructor.

In general binding like that in the constructor works only if you depend on props, but at that point, there isn't a need to bind at all since you can just reference the prop in the callback.


If you do that in the parent constructor it only really works for a single child and then you're better off not partially evaluating and instead having it pull props.bar at execution time


Sure, it would be an odd pattern but perhaps a required one for a certain interface.

eg: it's going to be used as a event callback but you want the function signature to be foo(bar, event). Then you get the benefits of partial application without the problems of currying a new function each time its called.

source: have used this a lot for event handlers, especially when dealing with on 3rd party code.


I don't quite understand. The interface is the same. I guess if the function you're binding is an external 3rd party one then you avoid proxying through a local function first. But there's no difference from the point of view of the child.

I guess my point was that it doesn't scale to multiple children (which is effectively what the question was about). And whether you want to partially apply a bound function in the constructor or just bind and then have the function pick up the extra arg itself - it's the same thing. You end up with a single function that works with a single constant.

Though, in your case if props change, the partially applied function is now incorrect. Which is why I think I'm misunderstanding you.


Right, I just used `props.bar` in that example, you're right - it would be a bad idea to do so unless it was some kind of initializing prop (common with state-based stuff).

> The interface is the same.

Huh? foo(event) is different from foo(bar, event) and if your function is only ever going to be called with the former (ie - any dom event handler) and you want the latter... it's absolutely useful.


I rather meant the interface between the partially applied foo and the version of foo that plucks bar from props when it's called.

Anyway, I see what you mean and it's a perfectly reasonable thing to do. Doesn't solve the original issue that was being discussed though :-)


Haven't tried this myself, but this might be what you're looking for: https://github.com/facebook/react-native/issues/9146#issueco...


Thanks! I'll give it a go.


Even though you picked the final designer as the winner, how did he know you were actually going to pay him?


99 Designs held the money in escrow. I suppose there is no guarantee that he would cooperate with what you want after you had awarded him the competition, but you can withhold the money indefinitely and it worked out fine for us.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: