James Elkwood
James Elkwood

Reputation: 155

React Native touchableopacity onpress not working

I'm new to react native (or any JS framework for that matter), and I'm trying to make a simple tap game where once you tap on the blue square it randomly renders in a different location, then you tap again, and so on. Here's my code so far:

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

import styles from './src/styles/style';

export default class App extends Component<{}> {

    constructor(props) {
        super();
        this.state = {
        showStartButton: true, // change back to true
        score: 0
    }
}

startGame() {
    this.setState({
       showStartButton: !this.state.showStartButton
    });
    this.renderFirstStage();
}

score() {
    this.setState({
        showStartButton: !this.state.showStartButton,
        score: score+1
    });
}

renderStartButton() {
    return (
        <TouchableOpacity style={styles.startButton} onPress={()=>this.startGame()}>
            <Text style={styles.startButtonText}>START</Text>
        </TouchableOpacity>
    );
}

renderWhiteBox() {
    return (
        <View style={{flex: 1, backgroundColor: 'white'}} />
    );
}

renderBlueBox() {
    return (
        <View style={{flex: 1, backgroundColor: 'blue'}} />
    );
}

renderFirstStage() {
    var blueColNum = Math.floor(Math.random() * 6);
    var blueRowNum = Math.floor(Math.random() * 4);
    var col1 = ['white', 'white', 'white', 'white', 'white', 'white'];
    var col2 = ['white', 'white', 'white', 'white', 'white', 'white'];
    var col3 = ['white', 'white', 'white', 'white', 'white', 'white'];
    var col4 = ['white', 'white', 'white', 'white', 'white', 'white'];

    if (blueRowNum == 0)
        col1[blueColNum] = 'blue';
    else if (blueRowNum == 1)
        col2[blueColNum] = 'blue';
    else if (blueRowNum == 2)
        col3[blueColNum] = 'blue';
    else if (blueRowNum == 3)
        col4[blueColNum] = 'blue';

    return (
        <View style={{flex: 1, flexDirection: 'row'}}>
            <View style={{flex: 1}}>
                <View style={styles.scoreBoard}><Text style={styles.timerText}>Time: {blueRowNum}</Text></View>
                {col1.map(function(el){
                    if (el == 'blue')
                        return (
                            <TouchableOpacity style={{flex: 1, backgroundColor: el}} onPress={()=>this.score()} />
                        );
                    else
                        return (
                            <View style={{flex: 1, backgroundColor: el}} />
                        );
                })}
            </View>
            <View style={{flex: 1}}>
                <View style={{flex: 1, backgroundColor: 'gray'}} />
                {col2.map(function(el){
                    if (el == 'blue')
                        return (
                            <TouchableOpacity style={{flex: 1, backgroundColor: el}} onPress={()=>this.score()}/>
                        );
                    else
                        return (
                            <View style={{flex: 1, backgroundColor: el}} />
                        );
                })}
            </View>
            <View style={{flex: 1}}>
                <View style={{flex: 1, backgroundColor: 'gray'}} />
                {col3.map(function(el){
                    if (el == 'blue')
                        return (
                            <TouchableOpacity style={{flex: 1, backgroundColor: el}} onPress={()=>this.score()} />
                        );
                    else
                        return (
                            <View style={{flex: 1, backgroundColor: el}} />
                        );
                })}
            </View>
            <View style={{flex: 1}}>
                <View style={styles.scoreBoard}><Text style={styles.timerText}>Score: {this.state.score}</Text></View>
                {col4.map(function(el){
                    if (el == 'blue')
                        return (
                            <TouchableOpacity style={{flex: 1, backgroundColor: el}} onPress={()=>this.score()} />
                        );
                    else
                        return (
                            <View style={{flex: 1, backgroundColor: el}} />
                        );
                })}
            </View>
        </View>
    );
}

render() {
    return (
        <View style={styles.container}>
            {this.state.showStartButton ? this.renderStartButton() : null}
                {!this.state.showStartButton ? this.renderFirstStage() : null}
            </View>
        );
    }
}

So that's a lot of code but I figured to include it all for context's sake. Anyways, the issue I'm having is with my renderFirstStage() function. See in the return statement where I'm calling an onPress event handler to run the function this.score? Ok, so when I run the program and I tap on one of those TouchableOpacities I get an error reading: _this5.score is not a function... _this5.score is undefined. My best guess is that since I'm calling the onPress={()=>this.score} from within JS code that is within JSX, and I somehow don't have access to methods in the App class. So I'm thinking something is wrong with the scope, or maybe not, I don't know. Even if my hunch is correct, I have no idea how to correct it. How can I call the score method from inside my TouchableOpacity components? Nothing I've tried seems to work for me...

Note: I'm running on an iPhone 7 emulator on a MacBook pro.

Upvotes: 1

Views: 5729

Answers (1)

Ahsan Ali
Ahsan Ali

Reputation: 5135

Yes it has the scope problem, you need to bind the function with this context in your constructor

constructor(props) {
    super();
    this.state = {
        showStartButton: true, // change back to true
        score: 0
    }
    this.renderFirstStage = this.renderFirstStage.bind(this);
}

Or you may simply use call to invoke the function immediately and bind it with this

{!this.state.showStartButton ? this.renderFirstStage.call(this) : null}

Upvotes: 1

Related Questions