Reputation: 2756
I iterate over a list of items and want to call a function onClick(). Example below:
class App extends Component {
state = { items: [1, 2, 3, 4] };
click = i => console.log(i);
render() {
return (
<div>
{this.state.items.map(item => (
<div
key={item}
// this works fine, but I rather not declare functions within the render function / JSX
onClick={() => this.click(item)}
>
{`click on # ${item}`}
</div>
))}
</div>
)
}
}
As you can see, I declare a function in the JSX. I do this over and over, but some time ago I learned that you should avoid declaring a function within the component JSX itself, for performance reasons.
Is this true, also for functional components? And if so, is there any other way to pass dynamic information (item, in this case) to a callback?
NOTE: I'm looking forward to using hooks at some point, but right now I just want to know a best practice without using them.
NOTE II: That being said, if you are sure that this is a relevant problem and it could not be solved until now because of hooks, I obviously would like to learn that :)
Upvotes: 0
Views: 1843
Reputation: 95
You can create a parent component which will be responsible for looping through the items and passing the click handler down as a prop to each individual child component.
Then inside the child component you can easily reference the handler as this.props.onClick
Functions (objects) are passed by reference in JavaScript. By declaring it in the parent scope it will only take up space there. If initialized in the child, it will create space in memory for the function with each child component.
class Parent extends Component {
state = { items: [1, 2, 3, 4] };
parentClick(item) {
// do something
console.log(item);
}
render() {
return (
<div>
{this.state.items.map(item => (
<Child item={item} onClick={this.parentClick}>
))}
</div>
)
}
}
class Child extends Component {
childClick(item) {
this.props.onClick(item)
}
render() {
return (
<div>
<p onClick={this.childClick(this.props.item)}>this.props.item</p>
</div>
)
}
}
Upvotes: 0
Reputation: 138267
Is this true, also for functional components?
Well actually there is no functional component used in your code. And everything you do in a function that gets called very often (render()
for example) causes performance to decrease, no matter wether that is a function or variable declaration or invokation. Wether that decrease matters is another thing.
And if so, is there any other way to pass dynamic information (item, in this case) to a callback?
You could .bind(...)
it:
onClick = {console.log.bind(console, item) }
but really, did you notice any delay on a rerender? Probably not, and if so that is not caused by the function declaration. Write code that looks beautiful to you, don't optimize for the compiler, let the compiler do that.
but some time ago I learned that you should avoid declaring a function within the component JSX itself
You shouldn't really avoid it, rather prefer other ways if possible. In this case there is not really a better way so go with it.
Upvotes: 1
Reputation: 1012
You can declare another method like this. Don't forget to use .bind
. Otherwise, the method won't be called correctly.
class App extends Component {
state = { items: [1, 2, 3, 4] };
handleClick(item) {
// do something
console.log(item);
}
render() {
return (
<div>
{this.state.items.map(item => (
<div
key={item}
// this works fine, but I rather not declare functions within the render function / JSX
onClick={this.handleClick.bind(this, item)}
>
{`click on # ${item}`}
</div>
))}
</div>
)
}
}
Upvotes: 0