-1

I'm trying to display a array from an array object using onClick event on a li , i am using arrow function but i found out i needed to bind the function inside the scope of map , why is that? Isn't that the purpose of arrow function to eliminate the need of binding?

 class ListRecipes extends React.Component   {

    showIngredients = (item) => {
        console.log(item.ingredients)
    }

    render() {
    const { list } = this.props;
    let Recipe = list.map((item, index) => {
        let boundClick = this.showIngredients.bind(this, item);
        return <li key={index} onClick={boundClick}> {item.recipeName} </li>
    })
    return (
        <div>
            <ul>
                {Recipe}
            </ul>
        </div>
        )
    }
}

Also what is the difference between this code that returns a new function from the above?

class ListRecipes extends React.Component   {

    showIngredients = (item) => (event) => {
        console.log(item.ingredients)
    }

    render() {
    const { list } = this.props;
    let Recipe = list.map((item, index) => {
        return <li key={index} onClick={this.showIngredients(item)}> {item.recipeName} </li>
    })
    return (
        <div>
            <ul>
                {Recipe}
            </ul>
        </div>
        )
    }
}
null
  • 1,062
  • 1
  • 9
  • 21
  • What happens when you *don't* bind it? What exactly does the code without binding look like? – deceze Dec 20 '17 at 09:31
  • if i don't bind it or return a new event function it console.log the array when the page loaded but not onClick. ` showIngredients = (item) => { console.log(item.ingredients) }` `onClick={this.showIngredients(item)}` – null Dec 20 '17 at 09:33

3 Answers3

0

When you write onClick={this.showIngredients(item)} you are not assigning a reference of function to onClick but calling it

You could change it to

let Recipe = list.map((item, index) => {
    return <li key={index} onClick={() => this.showIngredients(item)}> {item.recipeName} </li>
})

Also with let boundClick = this.showIngredients.bind(this, item); you are binding the showIngredients function to the context and passing an extra argument to it and since bind returns a new function so , boundClick is a function which is then later assigned to onClick

Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • I know about this, but they said to avoid inline functions. – null Dec 20 '17 at 09:36
  • @Juan Well, then `bind` it is. That has nothing to do with arrow functions and the value of `this`, just *when* you call the function. – deceze Dec 20 '17 at 09:37
  • @Shubham thanks for answering, also i want to know what is the difference between returning a new event and the binding in the post code. – null Dec 20 '17 at 09:39
  • Check this answer https://stackoverflow.com/questions/45053622/how-to-avoid-binding-inside-render-method/45053753#45053753 on how to avoid bind in render – Shubham Khatri Dec 20 '17 at 09:39
0

I think this code is generally preferred:

let boundClick = this.showIngredients.bind(this, item);

You are binding the item to be passed to the showIngredients function. So you end up creating items.length number of separate function references, each bound to this and the current item.

brub
  • 1,083
  • 8
  • 18
0

Before anything else we need to understand that the passed argument in callback listener on onClick is event. That mean

function myMethod(event) {
  // only event is passed as argument
}
<div onClick={myMehtod}/>

So question is how can you pass additional argument then? Simple. Call your desired method from the listener.

function calculate(item){
  // no event trace here
}

<div onClick={function(event) { calculate(item) }}/>
// OR better, fat arrow
<div onClick={event => calculate(item)}/>

Remember the fat arrow is always bind to this scope rather then to prototype.

class Component {
  scopedMethod = () => {
     this.name = 'John';
  }
  prototypeMethod() {
    this.name = 'John';
  }
  render() {
    return (
      <div>
        {/* works */}
        <button onClick={this.scopedMethod}/>
        {/* OOPS, 'this' is event rather then component */}
        <button onClick={this.prototypeMethod}/>
        {/* works */}
        <button onClick={() => this.prototypeMethod()}/>
        {/* works */}
        <button onClick={this.prototypeMethod.bind(this)}/>
      </div>
    )
  }
}

Hopefully that's brought a light in. So the question would be when and why I would to use scope binded method over prototype method and vice versa? Well, prototype methods are cheap. Always try to use them. However some developer are avoiding lambda function (generate function inside render) because it can cause performance issue. When you need to re-render your component 10x in second, then the new lambda is created 10x.

Eduard Jacko
  • 1,974
  • 1
  • 16
  • 29