2

I am checking the arrow function introduced in ES6. If I have this piece of code with the function "addNinja":

 addNinja=(ninja)=>{
         ninja.id=Math.random();
         let ninjas=[...this.state.ninjas,ninja];
         this.setState({
             ninjas:ninjas
         })
        console.log(this.state);

 }

Is there any way that this can be written without the arrow function?

If I taking into account that these 2 are the same...

x=>x*2 

function(x){
return x*2;
}

I will assume that I could rewrite the addNinja function like the code below but I get an error.

 addNinja=function(ninja){
         ninja.id=Math.random();
         let ninjas=[...this.state.ninjas,ninja]; 
         this.setState({
             ninjas:ninjas
         })
        console.log(this.state);

 }
Oscar Franco
  • 5,691
  • 5
  • 34
  • 56
Spaniard
  • 13
  • 9
  • 4
    *"but I get an error"* - The error message might be a clue as to what the error is. Though if I'm to guess I'd think the binding of `this` is different between the two. – David Feb 14 '19 at 12:17
  • 4
    unfortunately just converting the arrow function to a regular function is unlikely to work because of the difference in how `this` is treated in both scenarios. – phuzi Feb 14 '19 at 12:18
  • the error is: Cannot read property 'ninjas' of undefined – Spaniard Feb 14 '19 at 12:20
  • "If I taking into account that these 2 are the same..." you'd be believing falsehoods. arrow functions cannot become methods (i.e. don't set `this` to the receiver object like "proper" functions, but treat `this` as any other variable under closure). – Amadan Feb 14 '19 at 12:23

1 Answers1

6

The function() {} syntax does not bind the local context to the function, that is why this.setState or this.state.something fails, because this is defined by the global lexical context, and the state does not exist in it. If you want to achieve this you have to manually bind the function:

constructor(props) {
  this.addNinja = this.addNinja.bind(this);
}

addNinja=function(ninja){
         ninja.id=Math.random();
         let ninjas=[...this.state.ninjas,ninja]; 
         this.setState({
             ninjas:ninjas
         })
        console.log(this.state);
}
Oscar Franco
  • 5,691
  • 5
  • 34
  • 56
  • 2
    It is unlikely `this` is `undefined` - it will be defined by its lexical context, which is likely to be the global object. Nevertheless +1. – Amadan Feb 14 '19 at 12:19
  • True, thanks, updated the answer – Oscar Franco Feb 14 '19 at 12:21
  • Just calling `this.addNinja.bind(this)` won't help, you will need to do something with the result. Also, this looks like a `class` body, and then you should use method syntax for `addNinja` – Bergi Feb 14 '19 at 12:32
  • I knew I was forgetting something :P – Oscar Franco Feb 14 '19 at 12:33
  • Just a simple question: Can you bind the class methods somewhere else than inside the constructor? If so, what is the advantage of doing it there? – Spaniard Feb 14 '19 at 13:51
  • Don't think so, the constructor function is called when the class is instanciated, therefore `this` is actually binded to the context, any other functions will not be binded to the context – Oscar Franco Feb 14 '19 at 14:30