How to pass extra params to your handlers functions with React?
Tags: react, javascript, webdev, frontend
Published: 2019-05-24 13:42:07

---
title: How to pass extra params to your handlers functions with React?
published: true
description: spoiler: cache the handlers
tags: #react, #javascript, #webdev, #frontend
---

So you want to render a list and pass extra data to your function with React.

Well, React does not handle this for you like Angular or Vue with some extra syntax in html would do (is this html anymore?).

```javascript
<li *ngFor="let hero of heroes" (click)="onSelect(hero)">
```

So how to bind data in React efficiently?

### Approach 0: Do not try this at home...or office

```javascript

const things = new Array(32).fill(1).map((el, index) => {
  return {
    index,
    some: 'data'
  };
});

// PLEASE DO NOT DO THIS. But if you want to, who cares ¯\_(ツ)_/¯
class Bad extends React.Component {
  constructor(props) {
    super(props);
    this.state = { message: 'Hello!' };
  }

  handle = el => {
    // WOW a function on every render for every element of the list!!
    alert(JSON.stringify(el));
  };

  render() {
    return (
      <ul>
        {things.map((el, index) => {
          return <li onClick={() => this.handle(el)}>{el.some + el.index</li>;
        })}
      </ul>
    );
  }
}
```

The problem here is the follow: **a function is created on every render for every element of the list!!!**

So how to solve this? The perfomance for short lists will be good enogh but this approach does not scale. The list could be dynamic or could come from a service call.

### Approach 1: Put data in DOM and get it in handler
```javascript
const things = new Array(32).fill(1).map((el, index) => {
  return {
    index,
    some: 'data'
  };
});
class Approach1 extends React.Component {
  handleClick = evt => {
    // get item stored in dom
    // PRO: single function
    // CONS: dom payload increase, stringify on every call but this is optional
    const item = JSON.parse(evt.target.dataset.item);
    const index = parseInt(evt.target.dataset.index);
    alert(JSON.stringify(item) + index);
  };
  render() {
    return (
      <ul>
        {things.map((el, index) => {
          return (
            <li
              data-item={JSON.stringify(el)}
              data-index={el.index}
              onClick={this.handleClick}
            >
              {el.some + el.index}
            </li>
          );
        })}
      </ul>
    );
  }
}
```

This approach is good, but if you have an item model too huge is not optimal.
**PRO: single function for every item in list**
**CONS: dom payload increases if you have huge data model**

### Approach 2: The best(?) and verbose approach

```javascript
const things = new Array(32).fill(1).map((el, index) => {
  return {
    index,
    some: 'data'
  };
});
class BestApproach extends React.Component {
  constructor(props) {
    super(props);
    this.state = { message: 'Hello!' };
    this.handlers = new Map();
  }
  getHandler = (el, index) => {
    if (!this.handlers.has(el)) {
      this.handlers.set(el, evt => {
        // do somenthing with the event
        alert(JSON.stringify(el) + index);
      });
    }
    return this.handlers.get(el);
  };

  componentWillMount() {
    this.handlers.clear();
  }
  render() {
    return (
      <ul>
        {things.map((el, index) => (<li onClick={this.getHandler(el, index)}>{el.some + el.index}</li>))}
      </ul>
    );
  }
}
```

In this way we create a function for every item but only when the first render occurs. The next time we have the cached function back from getHandler.

### Approach 3: Event delegation. Probably the best one

```javascript
const things = new Array(32).fill(1).map((el, index) => {
  return {
    index,
    some: 'data'
  };
});

class MyLi extends React.Component {
  _handler = (evt) => {
    const { item, onPress } = this.props;
    onPress(item, evt);
  }
  render() {
    return <li onClick={this._handler}>{this.props.children}</li>;
  }
}
class BestOfBestApproach extends React.Component {
  constructor(props) {
    super(props);
    this.state = { message: 'Hello!' };
    this.handlers = new Map();
  }
  handler = ({ index, some }) => {
    alert(some);
  };

  render() {
    return (<ul>
      {things.map((el, index) => (<MyLi onPress={this.handler}>{el.some + el.index}</MyLi>))}
    </ul>);
  }
}
```

{% codesandbox react-cache-handlers-585c9 %}

Please comment if you have some better solution/approach or if you see some errors.

Bye and happy React coding!