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?

5 Answers 5

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)} />
Sign up to request clarification or add additional context in comments.

5 Comments

This is the exact same as an "inline" function.
Yes, but it doesn't trigger the no-bind rule which is what was asked here
Code: answer = 0. Compiler: Answer should not be 0. Revised Code: answer = 1-1
I agree, but sometimes, especially in big companies, you can't change the ESLint configuration and you have to work around it 🤷
Then you can disable the one line with a comment letting you know that you acknowledge the issue as opposed to obfuscating it and hiding it.
2

You can try this:

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

3 Comments

That's an inline function. As I said in the post, I want to avoid that.
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
Yes, that is what I'm trying to follow. But it's not clear how to handle both the event and an additional value.
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);
  }
});

Comments

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

Comments

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.