Rahul Salinskee
Rahul Salinskee

Reputation: 31

Reach Click handler from parent to child component is not working

I am very new in the world of React, so I am not sure what I am doing wrong. I have a click handler in parent component which needs to be passed the button element of child component.

Parent Component is 'LogStatus'

import React, { Component } from 'react';
import DisplayMessage from './DisplayMessage'
class LogStatus extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            isLogin: true,
        }
        this.btnChangeStatusClickHandler = this.btnChangeStatusClickHandler.bind(this);
    }

    btnChangeStatusClickHandler() {
        this.setState(previousState =>
            previousState.isLogin = !this.state.isLogin,
        )
    }

    render() {
        let statusMessage = '';
        if (this.state.isLogin === true) {
            statusMessage = 'Login';
        }
        else {
            statusMessage = 'Logoff'
        }
        return (
            <div>
                <DisplayMessage statusMessage={statusMessage} loginStatusHandler={this.btnChangeStatusClickHandler} />
            </div>
        );
    }
}

export default LogStatus;

Child Component is 'DisplayMessage'

import React, { Component } from 'react';
class DisplayMessage extends Component {
    constructor(props) {
        super(props);
        this.state = {
            statusMessage: props.statusMessage,
            btnStatusClickHandler: props.loginStatusHandler,
        }
    }
    render() {
        let displayBtnMessage = '';
        if (this.state.statusMessage === 'Login') {
            displayBtnMessage = "Logoff";
        }
        else {
            displayBtnMessage = 'Login';
        }
        return (
            <div>
                <h3>Login Status: {this.state.statusMessage}</h3>
                <button onClick={this.state.btnStatusClickHandler}>{displayBtnMessage}</button>
            </div>
        );
    }
}

export default DisplayMessage;

Working Code for the reference:

Parent Component is 'LogStatus'

import React, { Component } from 'react';
import DisplayMessage from './DisplayMessage'
class LogStatus extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            isLogin: true,
            displayStatus: '',
        }
        this.btnChangeStatusClickHandler =     this.btnChangeStatusClickHandler.bind(this);
    }

    btnChangeStatusClickHandler() {
        this.setState(previousState => {
            if (this.state.isLogin === true) {
                return {
                    displayStatus: 'Login',
                    isLogin: !previousState.isLogin,
                }
            }
            else {
                return {
                    displayStatus: 'Logoff',
                    isLogin: !previousState.isLogin,
                }
            }
        })
    }

    render() {
        return (
            <div>
                <DisplayMessage statusMessage={this.state.displayStatus} loginStatusHandler={this.btnChangeStatusClickHandler} />
            </div>
        );
    }
}

export default LogStatus;

Child Component is 'DisplayMessage'

import React, { Component } from 'react';
class DisplayMessage extends Component {
    render() {
        const { statusMessage, loginStatusHandler } = this.props;
        let displayBtnMessage = '';
        if (statusMessage === 'Login') {
            displayBtnMessage = "Logoff";
        }
        else {
            displayBtnMessage = 'Login';
        }
        return (
            <div>
                <h3>Login Status: {statusMessage}</h3>
                <button onClick={loginStatusHandler}>{displayBtnMessage}</button>
            </div>
        );
    }
}

export default DisplayMessage;

Upvotes: 1

Views: 56

Answers (1)

Chris
Chris

Reputation: 6631

You need two changes in your code;

1. Make sure the context is correct of your click handler

You btnChangeStatusClickHandler is currently a method of your class component. However, calling this function will use a global context (this). So this.setState will not work. You can fix this by turning the method in an arrow function member instead:

Change:

    btnChangeStatusClickHandler() {
        this.setState(previousState =>
            previousState.isLogin = !this.state.isLogin,
        )
    }

To:

    btnChangeStatusClickHandler = () => {
        this.setState(previousState =>
            previousState.isLogin = !this.state.isLogin,
        )
    }

2. Don't delegate your click handler in the state

It is not needed (and not recommended) to delegate your click handler and other props in the component state. You should always use event handlers and other properties from props directly so it can deal with changes.

import React, { Component } from 'react';

class DisplayMessage extends Component {
    render() {
        const { statusMessage, loginStatusHandler } = this.props;
        let displayBtnMessage = '';

        if (statusMessage === 'Login') {
            displayBtnMessage = "Logoff";
        }
        else {
            displayBtnMessage = 'Login';
        }

        return (
            <div>
                <h3>Login Status: {statusMessage}</h3>
                <button onClick={loginStatusHandler}>{displayBtnMessage}</button>
            </div>
        );
    }
}

export default DisplayMessage;

Upvotes: 1

Related Questions