Uncaught TypeError: Cannot read property 'state or props' of undefined

橙三吉。 提交于 2019-12-16 19:46:21

问题


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 ?


回答1:


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);
}



回答2:


I agree with all different solutions given by @Shubham Kathri except direct binding in render.

You are not recommended to bind your functions directly in render. You are recommended to bind it in constructor always because if you do binding directly in render then whenever your component renders Webpack will create a new function/object in bundled file thus the Webpack bundle file size grows. For many reasons your component re-renders eg: doing setState but if you place it in constructor it gets called called only once.

The below implementation is not recommended

<Child onCodeChange={this.setCodeChange.bind(this)} onLogin={this.login.bind(this)} />

Do it in constructor always and use the ref wherever required

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

<Child onCodeChange={this.setCodeChange} onLogin={this.login} />

If you are using ES6 then manual binding is not required but if you want you can. You can use arrow functions if you want to stay away with scope related issues and manual function/object bindings.

Sorry if there are any typos I am answering in my mobile



来源:https://stackoverflow.com/questions/39503559/uncaught-typeerror-cannot-read-property-state-or-props-of-undefined

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!