s2t2 s2t2 - 1 month ago 8
Javascript Question

Method inside anonymous function inside map is undefined

How does one invoke

handleButtonPress
inside the message map in this example React component?

import React, { Component } from 'react';
import {View, Text, TouchableOpacity} from 'react-native';

export default class MyComponent extends Component {
constructor(props){
super(props)
this.state = {messages:["THANKS", "MERCI", "GRAZIE"]}
this.myFunc = this.myFunc.bind(this)
this.handleButtonPress = this.handleButtonPress.bind(this)
}

render(){
return (
<View>
<Text>{this.state.message}</Text>

{
this.state.messages.map(function(message, index){
return (
<TouchableOpacity key={index} onPress={function(){ this.handleButtonPress(message) }.bind(this) }>
<Text>Press Me</Text>
</TouchableOpacity>
)
})
}

</View>
)
}

handleButtonPress(message){
console.log("BUTTON WAS PRESSED WITH MESSAGE: " + message)
this.myFunc(message)
}

myFunc(message){
console.log("MY FUNCTION WAS CALLED")
this.setState({message:message})
}

}


Right now it's throwing:
undefined is not a function (evaluating 'this.handleButtonPress(message)')
. Why is that so?

Answer

The problem is that Array.prototype.map doesn't bind a this context unless explicitly told to. From the documentation:

If a thisArg parameter is provided to map, it will be passed to callback when invoked, for use as its this value. Otherwise, the value undefined will be passed for use as its this value.

Since you never specify a this value, it is undefined, and doing thus the this that is bound to the anonymous function in onPress is undefined. That throws the error because there is no function handleButtonPress of undefined. This means you need to pass a this context to map, and from the documentation:

Syntax

arr.map(callback[, thisArg])

This will be applied like so:

{
    this.state.messages.map(function(message, index){
        return (
          <TouchableOpacity key={index} onPress={function(){ this.handleButtonPress(message) }.bind(this) }>
            <Text>Press Me</Text>
          </TouchableOpacity>
        )
    }, this) //Notice the `this` here, this is the optional thisArg which is used as the `this` value in the callback.
}

The this is the class when passed to map. It will then be bound to onPress's event handler (the anonymous function) and then call correctly.