nixgadgets nixgadgets - 2 months ago 25
React JSX Question

Binding error on React causing this.state is undefined with ES6

So I started converting my application from ES2015 to ES6 which uses React.

I have a parent class and a child class like so,

export default class Parent extends Component {
constructor(props) {
super(props);
this.state = {
code: ''
};
}

setCodeChange(newCode) {
this.setState({code: newCode});
}


login() {
if (this.state.code == "") {
// Some functionality
}
}

render() {
return (
<div>
<Child onCodeChange={this.setCodeChange} onLogin={this.login} />
</div>
);
}
}


Child class,

export default class Child extends Component {
constructor(props) {
super(props);
}

handleCodeChange(e) {
this.props.onCodeChange(e.target.value);
}

login() {
this.props.onLogin();
}

render() {
return (
<div>
<input name="code" onChange={this.handleCodeChange.bind(this)}/>
</div>
<button id="login" onClick={this.login.bind(this)}>
);
}
}

Child.propTypes = {
onCodeChange: React.PropTypes.func,
onLogin: React.PropTypes.func
};


However this causes the following error,

this.state is undefined

It refers to,

if (this.state.code == "") {
// Some functionality
}


Any idea what could be causing this ?

Answer

You can use arrow function to bind you functions. You need to bind you functions both in child as well as parent components.

Parent:

export default class Parent extends Component {
    constructor(props) {
        super(props);
        this.state = {
            code: ''
        };
    }

    setCodeChange = (newCode) => {
        this.setState({code: newCode});
    }


    login = () => {
        if (this.state.code == "") {
            // Some functionality
        }
    }

    render() {
        return (
            <div>
                <Child onCodeChange={this.setCodeChange} onLogin={this.login} />
            </div>
        );
    }
}

Child

export default class Child extends Component {
    constructor(props) {
        super(props);
    }

    handleCodeChange = (e) => {
        this.props.onCodeChange(e.target.value);
    }

    login = () => {
        this.props.onLogin();
    }

    render() {
        return (
            <div>
                <input name="code" onChange={this.handleCodeChange}/>
            </div>
            <button id="login" onClick={this.login}>
        );
    }
}

Child.propTypes = {
    onCodeChange: React.PropTypes.func,
    onLogin: React.PropTypes.func
};

There are other ways to bind the functions as well such as the one you are using but you need to do that for parent component too as <Child onCodeChange={this.setCodeChange.bind(this)} onLogin={this.login.bind(this)} />

or you can specify binding in the constructor as

Parent:

constructor(props) {
    super(props);
    this.state = {
        code: ''
    };
 this.setCodeChange = this.setCodeChange.bind(this);
 this.login = this.login.bind(this);
}

Child

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