103

How to pass extra parameters to an onClick event using the ES6 syntax?

For instance:

handleRemove = (e) => {

}

render() {
     <button onClick={this.handleRemove}></button>
}

I want to pass an id to the handleRemove function like this:

<button onClick={this.handleRemove(id)}></button>
0

9 Answers 9

176

Remember that in onClick={ ... }, the ... is a JavaScript expression. So

... onClick={this.handleRemove(id)}

is the same as

var val = this.handleRemove(id);
... onClick={val}

In other words, you call this.handleRemove(id) immediately, and pass that value to onClick, which isn't what you want.

Instead, you want to create a new function with one of the arguments already prefilled; essentially, you want the following:

var newFn = function() {
  var args = Array.prototype.slice.call(arguments);

  // args[0] contains the event object
  this.handleRemove.apply(this, [id].concat(args));
}
... onClick={newFn}

There is a way to express this in ES5 JavaScript: Function.prototype.bind.

... onClick={this.handleRemove.bind(this, id)}

If you use React.createClass, React automatically binds this for you on instance methods, and it may complain unless you change it to this.handleRemove.bind(null, id).

You can also simply define the function inline; this is made shorter with arrow functions if your environment or transpiler supports them:

... onClick={() => this.handleRemove(id)}

If you need access to the event, you can just pass it along:

... onClick={(evt) => this.handleRemove(id, evt)}
Sign up to request clarification or add additional context in comments.

4 Comments

how to use event.preventDefault() along with this.handleRemove(id,etv) inside onClick function in this way(es6).
worth mentioning that arrow function would cause a re-render every time, since new function is created on each render
Someone should definitely write about this "gotcha" (perhaps a blog post)? I would write about this, but I'm learning ReactJS (and advanced Javascript), but this tip is vitally important. So, as newbie, I did this._deleteText(result.text), and when my table loaded, each table row with a delete button fired off delete calls... ouch!
Something to note, adding the arrow function in the render method will create a new function on every new render. It will work, though. It's better to create the new bound function in the constructor and add the new function to the render method.
55

Use the value attribute of the button element to pass the id, as

<button onClick={this.handleRemove} value={id}>Remove</button>

and then in handleRemove, read the value from event as:

handleRemove(event) {
...
 remove(event.target.value);
...
}

This way you avoid creating a new function (when compared to using an arrow function) every time this component is re-rendered.

4 Comments

Nice and easy. Had an issue when the button had a icon/glyph in it though with the value being undefined. Just use event.currentTarget.value instead of event.target.value and all is good.
Glad it helped you. In my example, I assumed that the <button> had no child elements except simple text and hence event.target.value would work fine. But in case you have child elements that can take click events, one will have to do what you have mentioned i.e. set the value on child also and read it off the event.currentTarget.value.
I find it cleaner to use a simple function here for event handling. Both the approaches of binding or creating a function that returns another function will create lot of garbage as a new function will be created and old one discarded to be garbage collected on each render .
I get Uncaught TypeError: Cannot read property 'handleRemove' of undefined. And this is even after doing this.handleRemove = this.handleRemove.bind(this); at the top of my constructor(props).
34

Use Arrow function like this:

<button onClick={()=>{this.handleRemove(id)}}></button>

3 Comments

This creates a new function on every render which is not great for performance. ESLint flags it by default: github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/…
@craigpatik so if you were to create a named function as a property initializer or via .bind in the constructor and use that in place of the anonymous arrow function as shown above it would prevent creating a new function on every render.. and you could still curry your 2nd this.handleRemove(id) function inside of it?
Linting error: JSX functions should not use arrow functions react/jsx-no-bind
18
onClick={this.handleRemove.bind(this, id)}

Using with arrow function

onClick={()=>{this.handleRemove(id)}}

5 Comments

Not sure why someone downvoted this. It worked for me. Is it considered bad form to do it this way?
No Cari...its perfect you can use this.
This is basically the same as the accepted answer. And it's not efficient since it's creating a new function on each render. You should bind your functions in the constructor, not in the render method. So, works but may have a high cost in performance.
Linting error: JSX props should not use .bind() react/jsx-no-bind
11

Something nobody has mentioned so far is to make handleRemove return a function.

You can do something like:

handleRemove = id => event => {
  // Do stuff with id and event
}

// render...
  return <button onClick={this.handleRemove(id)} />

However all of these solutions have the downside of creating a new function on each render. Better to create a new component for Button which gets passed the id and the handleRemove separately.

3 Comments

I'm not sure why this is upvoted, 3 times! This does not bind the this.handleRemove function to the onClick event, this executes it immediately when the component renders, then bind whatever it returns to the onClick event.
@GiovanniLobitos In the end you get a function which has access to id and event and performs the duties of handleRemove(). Not sure what the issue you have with it is? Did you face any problems implementing? "Whatever it returns" is the aforementioned function with access to id and event.
I see. Got confused right there. Thanks for the clarification.
4

TL;DR:

Don't bind function (nor use arrow functions) inside render method. See official recommendations.

https://reactjs.org/docs/faq-functions.html


So, there's an accepted answer and a couple more that points the same. And also there are some comments preventing people from using bind within the render method, and also avoiding arrow functions there for the same reason (those functions will be created once again and again on each render). But there's no example, so I'm writing one.

Basically, you have to bind your functions in the constructor.

class Actions extends Component {

    static propTypes = {
        entity_id: PropTypes.number,
        contact_id: PropTypes.number,
        onReplace: PropTypes.func.isRequired,
        onTransfer: PropTypes.func.isRequired
    }

    constructor() {
        super();
        this.onReplace = this.onReplace.bind(this);
        this.onTransfer = this.onTransfer.bind(this);
    }

    onReplace() {
        this.props.onReplace(this.props.entity_id, this.props.contact_id);
    }

    onTransfer() {
        this.props.onTransfer(this.props.entity_id, this.props.contact_id);
    }

    render() {
        return (
            <div className="actions">
                <button className="btn btn-circle btn-icon-only btn-default"
                    onClick={this.onReplace}
                    title="Replace">
                        <i className="fa fa-refresh"></i>
                </button>
                <button className="btn btn-circle btn-icon-only btn-default"
                    onClick={this.onTransfer}
                    title="Transfer">
                    <i className="fa fa-share"></i>
                </button>                                 
            </div>
        )
    }
}

export default Actions

Key lines are:

constructor

this.onReplace = this.onReplace.bind(this);

method

onReplace() {
    this.props.onReplace(this.props.entity_id, this.props.contact_id);
}

render

onClick={this.onReplace}

5 Comments

'PropTypes' is not defined. You're missing something.
Of course @vapcguy. You have to import it: import PropTypes from 'prop-types'
Excellent answer - would be curious to see how it works with this.setState instead of props. I'm missing something on my end to close the loop.
and what if those functions are defined as constant variables?
@akkonrad, it would be the same. Fact is, there's a new function created on heap each time the render method is executed. However, notice that this changed now that we have react hooks, and declaring functions at render time is common practice, but only with hooks as far as I can tell, because react team take care of the performance in that case.
4

in function component, this works great - a new React user since 2020 :)

handleRemove = (e, id) => {
    //removeById(id);
}

return(<button onClick={(e)=> handleRemove(e, id)}></button> )

Comments

2

I use the following code:

<Button onClick={this.onSubmit} id={item.key} value={shop.ethereum}>
    Approve
</Button>

Then inside the method:

onSubmit = async event => {
    event.preventDefault();
    event.persist();
    console.log("Param passed => Eth addrs: ", event.target.value)
    console.log("Param passed => id: ", event.target.id)
    ...
}

As a result:

Param passed in event => Eth addrs: 0x4D86c35fdC080Ce449E89C6BC058E6cc4a4D49A6

Param passed in event => id: Mlz4OTBSwcgPLBzVZ7BQbwVjGip1

1 Comment

This is a duplicate answer. See Praym's solution.
0

I am using React-Bootstrap. The onSelect trigger for dropdowns were not allowing me to pass data. Just the event. So remember you can just set any values as attributes and pick them up from the function using javascript. Picking up those attributes you set in that event target.

    let currentTarget = event.target;
    let currentId = currentTarget.getAttribute('data-id');
    let currentValue = currentTarget.getAttribute('data-value');

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.