rpivovar
rpivovar

Reputation: 3438

How to get multiple refs to use the same handleClick function?

I have a few similar elements:

 <div ref={this.ref1} onClick={this.handleClick} className="icon-wrapper"></div>
 <div ref={this.ref2} onClick={this.handleClick} className="icon-wrapper"></div>
 <div ref={this.ref3} onClick={this.handleClick} className="icon-wrapper"></div>

In my constructor, I declare these refs:

constructor(props) {

    super(props);

    this.ref1 = React.createRef();
    this.ref2 = React.createRef();
    this.ref3 = React.createRef();

}

I'm trying to pass these refs to their respective handleClick() functions. Something like:

 <div ref={this.ref1} onClick={this.handleClick(ref1)} className="icon-wrapper"></div>

or

 <div ref={this.ref1} onClick={this.handleClick(this.ref)} className="icon-wrapper"></div>

And I'm trying to handle the ref in the handleClick function like this:

handleClick = (ref) => {
    console.log(ref);
}

And just as a ridiculously wild guess, I tried:

handleClick = () => {
    console.log(this.ref.current);
}

That all seems dead wrong because onClick={this.handleClick(ref)} would invoke the function immediately, which is not what is wanted from a click function.

How do you pass different refs to the same function so that the function knows who called it?

Upvotes: 1

Views: 490

Answers (2)

Avin Kavish
Avin Kavish

Reputation: 8947

The answer to your question is to use a lambda method,

 <div ref={this.ref1} onClick={() => this.handleClick(this.ref1)} className="icon-wrapper"></div>
 <div ref={this.ref2} onClick={() => this.handleClick(this.ref2)} className="icon-wrapper"></div>
 <div ref={this.ref3} onClick={() => this.handleClick(this.ref3)} className="icon-wrapper"></div>

But if what you want to do is to access the target that fired the event, you can use

handleClick = (event) => {
    console.log(event.target);
}

<div onClick={this.handleClick} className="icon-wrapper"></div>

Edit: Here are some alternatives with better (marginal) performance.

handleClick1 = () => this.handleClick(this.ref1)

handleClick1 = this.handleClick.bind(this, this.ref1)

render() {
  return (<div ref={this.ref1} onClick={this.handleClick1} className="icon-wrapper"></div>)
}

Upvotes: 1

John Ruddell
John Ruddell

Reputation: 25842

The main issue here is you are invoking the function immediately. Thats what applying () does to the end of a function. Instead you need to pass a callback function that needs to be invoked by the event. This is done by passing the function reference.

You can use bind here if you need to pass a value. .bind will return a new function to be invoked. null as the first argument is for the this context, null wont change its context assuming its already been bound to your class. If you need to bind this method you can just pass this through instead of null.

I would recommend passing something to map though instead of the whole ref, like so

<div ref={this.ref1} onClick={this.handleClick.bind(null, 'ref1')} className="icon-wrapper"></div>

then you would access like so

handleClick = (ref, event) => {
    if (!this[ref]) return
    console.log(this[ref].current);
}

Most use cases for passing a parameter to your function would be because you need a specific key. In this case it looks like you just want to access the element itself. You can get that from the event itself.

<div onClick={this.handleClick} className="icon-wrapper"></div>

handleClick = (event) => {
    console.log(event.target);
}

Upvotes: 1

Related Questions