TheRealFakeNews
TheRealFakeNews

Reputation: 8153

How to pass the event argument when binding functions in React?

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

Answers (5)

monkey king
monkey king

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

juanecabellob
juanecabellob

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

funwhilelost
funwhilelost

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

Gio Polvara
Gio Polvara

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

Fleezey
Fleezey

Reputation: 166

You can try this:

<input
  onChange={(e) => this._onChangeHandler(e, someValue)}
/>

Upvotes: 2

Related Questions