Reputation: 427
I have this React component that has items generated from a list (with a map function). Each of those elements has a button. I want this button's onclick button to pass in a parameter to identify which list item's button was clicked.
It looks something like this.
var Component = React.createClass({
assignItem: function(item){
this.setState({item:item})
},
render: function(){
var listItems = list.map(function(item){
return <div>{item}
<button onClick={this.assignItem(item)>Click</button>
</div>
})
return <div>{listItems}</div>
}
})
Of course that doesn't work. The error message says that this.assignItem is not a function. I know the official React documentation suggests this:
var handleClick = function(i, props) {
console.log('You clicked: ' + props.items[i]);
}
function GroceryList(props) {
return (
<div>
{props.items.map(function(item, i) {
return (
<div onClick={handleClick.bind(this, i, props)} key={i}>{item}</div>
);
})}
</div>
);
}
ReactDOM.render(
<GroceryList items={['Apple', 'Banana', 'Cranberry']} />, mountNode
);
but that works with a function outside of the component. Since I want my function to manipulate the sate, I want to keep it within the React component.
How do I do this?
Upvotes: 4
Views: 17264
Reputation: 52183
You can bind
to a function on this
just like the React example, however since you are rendering in a map
callback you need to either pass in thisArg
or use a fat arrow function:
var Component = React.createClass({
assignItem: function(item){
this.setState({item:item})
},
render: function(){
// bind to this.assignItem
var listItems = list.map(function(item){
return <div>{item}
<button onClick={this.assignItem.bind(this, item)}>Click</button>
</div>
}, this); // pass in this, or use fat arrow map callback
return <div>{listItems}</div>
}
})
This is an old question using an old React API and an accordingly old answer. Today you should be using the class or functional React component API. For passing arguments to click handlers you can just write an inline fat arrow function and call through with whatever params you want. The above example ends up like this:
class MyComponent extends React.Component { // or React.PureComponent
assignItem = item => { // bound arrow function handler
this.setState({ item: item });
}
render() {
var listItems = list.map(item => {
// onClick is an arrow function that calls this.assignItem
return <div>{item}
<button onClick={e => this.assignItem(item)}>Click</button>
</div>
});
return <div>{ listItems }</div>
}
}
Note: The assignItem
handler must be bound, which is done here using an arrow function as a class property.
Upvotes: 15