News for hackers. Stuff that matters.
Re:Optimizing React Rendering by positivecomment on Thursday May 25, 2017 @01:05PM (#14418557)
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 <Data data={d} index={i} onDelete={this.handleDelete} />
        });
    }
    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 function. Is there a better way?
Re:Optimizing React Rendering by nip on Thursday May 25, 2017 @01:18PM (#14418647)
Re:Optimizing React Rendering by Silhouette on Thursday May 25, 2017 @02:31PM (#14419126)
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 by azundo on Thursday May 25, 2017 @04:07PM (#14419768)
Another is to wrap the first option in _.memoize so you only create functions once per argument and you don't get unnecessary rerenders. Just remember that _.memoize only uses the first arg for cache lookups.
Re:Optimizing React Rendering by dounan on Thursday May 25, 2017 @01:46PM (#14418832)
> 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 :)

Re:Optimizing React Rendering by doctorcroc on Thursday May 25, 2017 @02:28PM (#14419107)
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!

Re:Optimizing React Rendering by dounan on Thursday May 25, 2017 @05:22PM (#14420241)
> 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.

Re:Optimizing React Rendering by kentor on Thursday May 25, 2017 @01:16PM (#14418632)
Nope. For dom elemenets I have been using `data-{name}` attributes, and pulling them out from the handler using `e.currentTarget.dataset.{name}`
Re:Optimizing React Rendering by zevyoura on Thursday May 25, 2017 @01:20PM (#14418657)
You can partially apply the function where you know the parameter; i.e. assign onDelete to: this.handleDelete.bind(this, i)
Re:Optimizing React Rendering by dounan on Thursday May 25, 2017 @01:45PM (#14418817)
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.
Re:Optimizing React Rendering by abritinthebay on Thursday May 25, 2017 @02:21PM (#14419066)
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 by dounan on Thursday May 25, 2017 @03:09PM (#14419364)
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.

Re:Optimizing React Rendering by aidos on Thursday May 25, 2017 @02:46PM (#14419228)
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
Re:Optimizing React Rendering by abritinthebay on Thursday May 25, 2017 @02:57PM (#14419309)
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.

Re:Optimizing React Rendering by aidos on Thursday May 25, 2017 @03:11PM (#14419372)
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.

Re:Optimizing React Rendering by abritinthebay on Thursday May 25, 2017 @03:31PM (#14419514)
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.

Re:Optimizing React Rendering by aidos on Thursday May 25, 2017 @04:19PM (#14419835)
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 :-)