Golan Kiviti
Golan Kiviti

Reputation: 4255

React - How to properly pass and invoke functions that accepts parameters to a component

I'm using react and I have read a lot of articles about how to use it properly and avoiding unnecessary re-rendering, and one of the topics was the way you pass functions to a component. So basically we need to avoid passing a different instance of a function like this:

<Component onClick={() => ... }/>

or

<Component onClick={this.method.bind(this)} />

and you should bind in the constructor the function and just pass as following:

this.method = this.method.bind(this);

<Component onClick={this.method} />

Which makes perfectly sense, but now, I have a method that accepts a parameter:

onPropertyChange(field, event) {
    ...
}

And I want this method to be invoked by an input whenever the value changed, the only way that I managed to do it is this:

<input onChange={this.onPropertyChange.bind(this, 'id')} />

That works perfectly since it binds the function to my component, passes the field and the event. But in this way it will pass a different instance each time, which will cause unnecessary re-rendering.

So how can I do it properly and avoid unnecessary re-rendering.

Upvotes: 1

Views: 1848

Answers (2)

David Gilbertson
David Gilbertson

Reputation: 4883

Sorry this is a bit of a non-answer, but I think the answer is that this:

<input onChange={this.onPropertyChange.bind(this, 'id')} />

or this

<input onChange={() => this.onPropertyChange('id')} />

is the "proper" way to do it.

Best practices are good, and the theory is sound, but is this premature optimisation? Or unquantified optimization?

Here's my performance tuning checklist. (TL:DR, time everything, fix what makes a difference.)

  1. Install and run React's perf tools to identify components that are rendering unnecessarily.
  2. If you have many components, there will be some that are rendering when they don't need to, but might only be costing one or two milliseconds. You can ignore them unless you envisage the number of them growing by an order of magnitude, or have nothing else to do.
  3. For the components that are wasting tens of milliseconds (or might one day), implement shouldComponentUpdate checks to ensure you only run render() when a change is required. Make sure you're checking all props that a child might use. Remember these can be a gotcha if you add data to your model later, you'll need to add that to your checks to ensure render runs.

Complexity is where the bugs hide, so if you're doing something that feels clunky and can't say exactly why, I would suggest that you shouldn't be doing the clunky thing.

Upvotes: 0

Tom Fenech
Tom Fenech

Reputation: 74695

The answer to your question really depends where id comes from.

If you have several fixed strings and want to avoid the "overhead" of creating a new anonymous function once per render, then you can create several bound copies in the constructor:

this.onIdChange = this.onPropertyChange.bind(this, 'id');
this.onNameChange = this.onPropertyChange.bind(this, 'name');

Then use:

<input onChange={this.onIdChange} />

I'd be wary of premature optimisation in this case, though. If you haven't determined for definite that creating anonymous functions in your render methods is killing the performance of your application, then I wouldn't assume it to be the case.

Note that your code:

<input onChange={this.onPropertyChange.bind(this, 'id')} />

is not triggering unnecessary re-renders. The only thing it is doing which could be perceived as "bad practice" is creating a new function every time a re-render is triggered. This will create some overhead but you should really do some profiling before assuming that it's going to cause problems.

Upvotes: 1

Related Questions