Jonathan Cameron
Jonathan Cameron

Reputation: 331

ReactJS - Child's onClick event calls parent method but the scope is not what I expected

I have a parent and child class. The parent class has a store and a method that needs to be called when the child is clicked. The parent method modifies the store. Unfortunately when I call the parent's method from the child's onClick (using props), the this object is not available. I believe this is a scoping issue but I don't know whether it's a JS level issue or a misunderstanding of React's scoping (I'm new to the framework).

The components are defined below, when I click on the Button span I get the following error out of toggleAlarmState:

Uncaught TypeError: Cannot read property 'setState' of undefined

Parent component

import Button from "../components/buttons/Button"

export default class TestStatus extends Component {

    state = {
        alarmIsOn: false,
    };

    toggleAlarmState(event) {
        this.setState({
                alarmIsOn: !this.state.alarmIsOn
            }
        )
    }

    render() {
        return (
            <Button
                className="alarm-toggle-btn"
                text={`Alarm is ${this.state.alarmIsOn ? 'On' : 'Off'}`}
                onClick={this.toggleAlarmState}
            />
        );
    }
} 

Child Component

import React, {Component} from "react";

export default class Btn extends Component {

    render() {
        return (
            <span onClick={this.props.onClick}>{this.props.text}</span>
        )
    }
}

Why is this undefined and what is the best practice for modifying the store when I click a button component?

Upvotes: 0

Views: 499

Answers (1)

Ajin Kabeer
Ajin Kabeer

Reputation: 2186

I think if you convert toggleAlarmState to an arrow function, it will work! or if you insist on using the same function, you have to bind toggleAlarmState with this inside your constructor.

toggleAlarmState = event => {
        this.setState({
                alarmIsOn: !this.state.alarmIsOn
            }
        )
    }

This is another solution with binding if you are not using an arrow function.

constructor( props ){
    super( props );
    this.toggleAlarmState = this.toggleAlarmState.bind(this);
  }

    state = {
    alarmIsOn: false,
};

toggleAlarmState(event) {
    this.setState({
            alarmIsOn: !this.state.alarmIsOn
        }
    )
}

Upvotes: 3

Related Questions