4

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?

Community
  • 1
  • 1
TheRealFakeNews
  • 7,512
  • 16
  • 73
  • 114

5 Answers5

4

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)} />
Gio Polvara
  • 23,416
  • 10
  • 66
  • 62
2

You can try this:

<input
  onChange={(e) => this._onChangeHandler(e, someValue)}
/>
Fleezey
  • 156
  • 7
  • That's an inline function. As I said in the post, I want to avoid that. – TheRealFakeNews Feb 14 '17 at 19:04
  • My bad, didn't know that rule implies no inline function. You could still create a new component with you onClick handler. Check the second example of these [es-lint protips](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md#protips) – Fleezey Feb 14 '17 at 19:09
  • Yes, that is what I'm trying to follow. But it's not clear how to handle both the event and an additional value. – TheRealFakeNews Feb 14 '17 at 19:15
1

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);
  }
});
funwhilelost
  • 1,990
  • 17
  • 20
1

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)} />
0

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.

juanecabellob
  • 458
  • 3
  • 14