user2205259
user2205259

Reputation: 563

Handle clicks in dynamically generated elements

I noticed this pattern a couple of times and started wondering what's actually the right way to handle it.

Let's say I have an array of objects for which I need to generate corresponding clickable elements. In a click handler, I want to have an access to the corresponding object.

render() {
  links = this.props.links.map(link => {
    <a
      onClick={this.clickHandle}>
      {link.title}
    </a>
  })
  // ...
}

However, with this approach, the clickHandle method will be called without any relevant information about the link object when the user clicks on the link. So to have an access to the corresponding object, I made use of closure property in clickHandle and rewrote it this way:

onClick={this.clickHandle(link)}
// ...
clickHandle(link) {
  return () => {
    alert(link)
  }
}

While it works as expected, I'm wondering if it's actually the right way to do it. It seems like I'm creating a lot of intermediate functions each time React rebuilds this piece of dom. Is it a bad practice? What are alternatives?

Upvotes: 2

Views: 64

Answers (2)

Felix Kling
Felix Kling

Reputation: 816324

What are alternatives?

Create a link component that gets the data as props and passes it to the click handler:

var Link = React.createClass({
    propTypes: {
        data: ...,
        onClick: React.PropTypes.func.isRequired,
    },

    _onClick: function() {
        this.props.onClick(this.props.data);
    },

    render: function() {
        return (
            <a
                onClick={this._onClick}>
                {this.pops.data.title}
            </a>
        );
    }
});

Usage:

links = this.props.links.map(
    link => <Link key={...} data={link} onClick={this.clickHandle} />
);

Upvotes: 2

gcedo
gcedo

Reputation: 4931

Even though it still creates intermediate functions, the React way is to use .bind().

render() {
  links = this.props.links.map(link => {
    <a
      onClick={this.clickHandle.bind(this, link}>
      {link.title}
    </a>
  })
  // ...
}

Upvotes: 2

Related Questions