Reputation: 6263
Ok, so I'm new to React, and there is one thing about event handlers that is really, really bothering me: I can't seem to get a straight answer about how to pass arguments to them. So far, there are two ways that I've seen:
Bindprops.squareClick.bind(this, argument)
Inline
onClick={() => props.squareClick(argument)}
The big thing I keep reading about is performance costs. Because inline functions or functions with Bind get treated as brand new functions on a re-render, there's extra GC overhead and, for class components, it can break shallow checks for shouldComponentRender with PureComponent.
Then there are some people saying this is over-optimization, that I shouldn't worry about it and just use an inline function. Which is cool, but honestly all of this conflicting information is leaving me confused.
So, I'm going to include a code example. It's take from a Tic-Tac-Toe app I made to practice React. It is a functional component for a single Square on the board. This component is re-used for all of the squares, and a key is passed in as a prop (ie, TOP_LEFT) to indicate which square it is. There's also a click handler where when the Square is clicked on, an event is sent back to the parent component. For the click handler to know which Square was clicked, that key property is passed in as an argument.
Please look at this code and give me feedback. Is this an acceptable practice in React? Will it incur a performance hit, and will that performance hit be substantial? Finally, if your answer is that I shouldn't do this, please clearly explain to me a better practice.
import React from 'react';
const Square = props => {
return (
<div onClick={() => props.squareClick(props.key)}>
<p>{props.value}</p>
</div>
);
};
export default Square;
Upvotes: 7
Views: 8698
Reputation: 1531
In React with Typescript to pass extra parameter to an event handler I do like this :
import React from 'react';
export default class MyComponent extends React.Component {
constructor(props: any) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
render() {
return (
<div>
<p onClick={(this.handleClick("Volvo"))}>Volvo</p>
<p onClick={this.handleClick("Saab")} >Saab</p>
<p onClick={this.handleClick("Mercedes")} >Mercedes</p>
<p onClick={this.handleClick("Audi")} >Audi</p>
<div id="selectResult">
</div>
</div>
);
}
handleClick(selected: string): ((event: React.MouseEvent<HTMLElement, MouseEvent>) => void) {
return (e) => {
e.preventDefault();
document.getElementById("selectResult")!.innerHTML = "You clicked: " + selected;
}
}
}
Also see the project for this example in Codpen
Upvotes: 1
Reputation: 2653
What I usually do is using datasets:
import React from 'react';
const Square = props => {
return (
<div
data-key={props.key}
onClick={props.squareClick}>
<p>{props.value}</p>
</div>
);
};
export default Square;
Then on the method itself, you just get back your value as e.target.dataset.key
.
Or you could also turn it to a class component :
import React from 'react';
class Square extends React.Component {
handleClick = e => {
this.props.squareClick(this.props.key)
}
render() {
return (
<div onClick={this.handleClick}>
<p>{this.props.value}</p>
</div>
);
}
};
export default Square;
Upvotes: 9
Reputation: 17598
For your example this can be used:
import React from 'react';
const Square = props => {
const handleClick = () => props.squareClick(props.key);
return (
<div onClick={handleClick}>
<p>{props.value}</p>
</div>
);
};
export default Square;
With this method, just using reference for a function, function itself won't recreated every time. But, for some situations people can't use a method something like this and seeking other solutions. There are multiple questions around here like this:
How to pass variables to a function reference?
Upvotes: 0