zaebalo
zaebalo

Reputation: 157

How to access state inside function which is inside of function inside of map

I'm trying to make onClick effect on every item of .map method like this:

this.props.products.map(function(item, i) { return ( <tr key={ i } onClick={ function() { console.log(arrayForOnClick) arrayForOnClick = [item['id'], item['name'], item['price']] this.handleTableString(item['id'], item['name'], item['price']) // Нужно передать айди, имя и цену в модальное окно при клике на этот <tr>. } }> <td>{ item['id'] }</td> <td>{ item['name'] }</td> <td>{ item['price'] }</td> </tr> ) }, this) And I'm trying to access this.handleTableString which is

handleTableString(id, name, price) { this.setState({ editProductModal: true, selectedId: id, selectedName: name, selectedPrice: price }) console.log('triggered') }

But I get error Uncaught TypeError: Cannot read property 'handleTableString' of null Is there another way to make that onClick or something is wrong with my code?

Upvotes: 0

Views: 858

Answers (4)

fkulikov
fkulikov

Reputation: 3199

In JavaScript this inside function can be bound to god-know-what, depending on how it was called. In your code this in line this.handleTableString(item['id'], ... is not pointing to the component.

Use ES6 arrow functions as your handlers both for map and onClick or use this-that trick in case you forced to use ES5 syntax and can't/don't want to use transpilers (Babel, obviously).

Upvotes: 0

Tharaka Wijebandara
Tharaka Wijebandara

Reputation: 8055

The problem is that this is null inside your onClick inline function. So you need to assign onClick to a function that this has been explicitly set using javascript bind method.

<tr key={ i } onClick={
  function() {
    console.log(arrayForOnClick)
    arrayForOnClick = [item['id'], item['name'], item['price']]
    this.handleTableString(item['id'], item['name'], item['price'])
  }.bind(this)
}>
...
</tr>

Upvotes: 0

ilyaigpetrov
ilyaigpetrov

Reputation: 3883

The problem is that this is different for each function (it is not preserved for your nested function). You may.

  1. Use variable to keep reference on this.

.

this.props.products.map(function(item, i) {

  const self = this;
  return (
    <tr key={ i } onClick={ function() {
        console.log(arrayForOnClick)
        arrayForOnClick = [item['id'], item['name'], item['price']]
        self.handleTableString(item['id'], item['name'], item['price'])
        // Нужно передать айди, имя и цену в модальное окно при клике на этот <tr>. 
      } }>
      <td>{ item['id'] }</td>
      <td>{ item['name'] }</td>
      <td>{ item['price'] }</td>
    </tr>
  )
}, this)
  1. Use arrow functions that don't bind this, so it is looked up in parent context.

.

this.props.products.map(function(item, i) {
  return (
    <tr key={ i } onClick={ () => {
        console.log(arrayForOnClick)
        arrayForOnClick = [item['id'], item['name'], item['price']]
        this.handleTableString(item['id'], item['name'], item['price'])
        // Нужно передать айди, имя и цену в модальное окно при клике на этот <tr>. 
      } }>
      <td>{ item['id'] }</td>
      <td>{ item['name'] }</td>
      <td>{ item['price'] }</td>
    </tr>
  )
}, this)

Upvotes: 1

dfsq
dfsq

Reputation: 193261

Don't create anonymous function like you are doing without binding context properly. It's cleaner to use arrow function in this case too:

this.props.products.map(function(item, i) {
  return (
    <tr key={ i } onClick={() => {
        const arrayForOnClick = [item['id'], item['name'], item['price']]
        this.handleTableString(item['id'], item['name'], item['price'])
      } }>
      <td>{ item['id'] }</td>
      <td>{ item['name'] }</td>
      <td>{ item['price'] }</td>
    </tr>
  )
}, this)

Upvotes: 0

Related Questions