1

I am trying to render a series of buttons from an array of objects.

const numbers = 
[{
key:"C",
id:"clear"
},{
key:"/",
id:"divide"
},
{
key:"*",
id:"multiply"
}]

I tried to use regular function. It renders the buttons, but it wouldn't trigger the click action.

{numbers.map( function(item) {
          return (<button class="button btn btn-light" id={item.id} onClick={this.handleClick}>{item.key}</button>);
        }

The following works

  {numbers.map( item=>
               <button class="button btn btn-light" id={item.id} onClick={this.handleClick}>{item.key}</button>)
  }

What do I need to change in regular function to make it behave like arrow function?

4 Answers 4

1

The below one doesn’t work because this context won’t be available inside regular function. You need to bind it so that this will be available.

Also class is reserved for declaring components in react so to add css class names to jsx elemebts you have to use className instead of class.

Also when you render jsx elements inside loop you must add unique key to top most element

Also make sure you bind handleClick in constructor if it is regular function in your code. If it is arrow function then no need to do manual binding

Change

  {numbers.map( function(item) {
      return (<button class="button btn btn-light" id={item.id} onClick={this.handleClick}>{item.key}</button>);
    })
  }

To

  {numbers.map(function(item) {
      return (<button key={item.id} className="button btn btn-light" id={item.id} onClick={this.handleClick}>{item.key}</button>);
    }.bind(this)
  )}

The second one in your question works because it uses arrow function

Sign up to request clarification or add additional context in comments.

Comments

1

I think it's this reference that's going bad in the first case. Try to verify it yourself by logging this in first case. The second code segment is the new ES6 syntax designed for this particular problem. If you're adamant on using first syntax, please add bind like below

{numbers.map( function(item) {
          return (<button class="button btn btn-light" id={item.id} onClick={this.handleClick.bind(this)}>{item.key}</button>);
        }

read this for more data on function context and this.

Comments

1

The problem is that the regular function declaration has its own value of this, which will be different from the component instance it's a method of. The arrow function works because arrow functions adopt the this of their surrounding lexical environment.

The alternative solution, suggested in the official React documentation, is to use bind. Put this.handleClick = this.handleClick.bind(this) in the component's constructor.

Comments

1

In ES5, The scope of 'this' refers to window object when we write in a standalone function.

var standAloneFunc = function(){alert(this)};

The arrow function was introduced to resolve 'this' issue, where 'this' refers to the function itself. it makes use of lexical scoping

var standAloneFunc = () => alert(this);

So, The issue in the your code is the scoping of 'this'.

{numbers.map( function(item) {
  return (<button class="button btn btn-light" id={item.id} onClick= 
  {this.handleClick}>{item.key}</button>);
 }

Here scope of 'this' refers to window object.

 {numbers.map( item=>
           <button class="button btn btn-light" id={item.id} onClick= 
     {this.handleClick}>{item.key}</button>)
 }

Here scope of 'this' refers to the parent function itself.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.