Reputation: 8153
I have an input
HTML tag, where the onChange
is currently
onChange={() => { this.props.someFunc(this.props.someVal, e.target.checked) }
However, I want to follow the es-lint no-bind
rule (I want to avoid inline functions), and I'm having issues hadling the arguments for this onChange function.
In my constructor I have:
constructor() {
super();
this.state = {
// some state
};
this._onChangeHandler = this._onChangeHandler.bind(this);
}
_this.onChangeHandler = (event, val) => {
this.props.someFunc(event.target.checked, val);
}
render() {
<div>
{
this.props.inputs.map((x) => {
const someValue = // ...a calculated value
return (
<label
}>
<input
onChange={ this._onChangeHandler(someValue) } // need BOTH someValue and the event
checked={ aBool }
type="checkbox"
value={ anotherValue }/>
<span>{ textHere }</span>
</label>
);
})
}
</div>
}
I've taken a look at this post, but no luck so far. What do I need to do to be able to pass both a value and the event to a bound function?
Upvotes: 4
Views: 4583
Reputation: 21
In the accepted currying solution above, the order of the arguments are wrong. Plus it does not handle multiple args when the handler is actually invoked. Here's an improved version:
// Helper method that returns a function - order matters here!!!
const generateHandler = (value, method) => (...e) => method(value, ...e)
// Apply the helper method
<input onChange={generateHandler(someValue, this._onChangeHandler)} />
Upvotes: 1
Reputation: 454
As you have your code at the moment, you receive in the event
input variable the values of someValue
and in the val
input variable the event object. That said, you just need to invert the order of your two input variables so you receive what you expect.
When you bind functions to events, your input variables will be called first and then you will get whatever the API of the event is defined to return.
Upvotes: 0
Reputation: 2010
From the es-lint example linked in Fleezey's comment. Here's what it would look like in your case:
var List = React.createClass({
constructor() {
super();
this._onChangeHandler = this._onChangeHandler.bind(this);
}
this._onChangeHandler = (event, val) => {
this.props.someFunc(event.target.checked, val);
}
render() {
<div>
{
this.props.inputs.map((x) => {
const someValue = // ...a calculated value
return (
<label>
<ListItem
onChange={ this._onChangeHandler }
changeHandlerValue={ someValue }
checked={ aBool }
value={ anotherValue } />
<span>{ textHere }</span>
</label>
);
})
}
</div>
}
});
var ListItem = React.createClass({
render() {
// render the input using the props passed in
return (
<input
onChange={this._onChange}
checked={this.props.checked}
type="checkbox"
value={this.props.value}
/>
);
},
_onChange(event) {
// trigger the event handler and pass both the event and the value
this.props.onChange(event, this.props.changeHandlerValue);
}
});
Upvotes: 1
Reputation: 26988
What if you use currying?
// Helper method that returns a function
const generateHandler = (value, method) => e => method(e, value)
// Apply the helper method
<input onChange={generateHandler(someValue, this._onChangeHandler)} />
Upvotes: 4
Reputation: 166
You can try this:
<input
onChange={(e) => this._onChangeHandler(e, someValue)}
/>
Upvotes: 2