React- Cannot read property 'setState' of

2019-03-26 07:38发布

for some reason, I'm getting the error " React- Cannot read property 'setState' of undefined". So this.state is never getting updated with the values that the user inputs. When I tried the binding that is commented out, I get strange behavior where I'm unable to type input for the username and I no longer get the null error, but the values are just undefined. Any help would be appreciated. Thanks.

import __fetch from "isomorphic-fetch";
import React from "react";
import InlineCss from "react-inline-css";
import Transmit from "react-transmit";

import Header from './components/header'

class Registration extends React.Component {

    componentWillMount () {
        if (__SERVER__) {
            console.log("Hello server from Registration");
        }

        if (__CLIENT__) {
            console.log("Hello Registration screen");
        }
    }

    constructor () {
        super()

        this.state = {
            name: '',
            password: ''
        }

         //this.onChangeName = this.onChangeName.bind(this);
         //this.onChangePassword = this.onChangePassword.bind(this);
    }

    onChangeName(e) {
        //this.state.name = e.target.name
        this.setState({ name: e.target.name});
    }

    onChangePassword(e) {
        //this.state.password = e.target.name
        this.setState({ password: e.target.password });
    }


    emptinessChecker(){
        let {name, password} = this.state
        console.log(name)
        if (name === "" || password === "") {
            return true;
        }
        else {
            return false;
        }
    }

    submit() {
        console.log(this)
        console.log(this.state)
        if (this.emptinessChecker()){
            alert("Please do not leave any fields blank!");
        }
        else{
            var xhr = new XMLHttpRequest();   // new HttpRequest instance 
            xhr.open("POST", "/edit");
            xhr.addEventListener("load", e => {
                console.log(xhr.responseText)
            });

            xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
            xhr.send(JSON.stringify(this.state));
            window.location.href= "/success"
        }
    }


    render () {

        //let {username, password} = this.state

        if (__SERVER__) {
            console.log("render server from registration");
        }
        if (__CLIENT__) {
            console.log('we client now!')
        }

        return (
            <InlineCss stylesheet={Registration.css()} namespace="Registration">
                <Header />



                <div>
                    <div className = "Register" >
                        Register
                    </div>


                    <ul className="account-fields">

                        <div className = 'Name'>
                                <label>Username</label>
                                <input type="text" value={this.state.name} onChange={this.onChangeName} />
                        </div>

                        <div className = 'Password'>
                                <label>Password</label>
                                <input type="password" value={this.state.password} onChange={this.onChangePassword} />
                        </div>


                        <div className='submitForm'>
                            <div className='submit' onClick={e=>this.submit()}>Submit</div>
                        </div>

                    </ul>
                </div>

            </InlineCss>




        );
    }
    /**
     * <InlineCss> component allows you to write a CSS stylesheet for your component. Target
     * your component with `&` and its children with `& selectors`. Be specific.
     */
    static css () {
        return (`
            & .Register {
                position: fixed;
                right: 550px;
                bottom: 550px;
                font-size: 50px;
            }
            & .account-fields {
                position: fixed;
                right: 550px;
                bottom: 450px;
                font-size: 20px;
            }
            & .submitForm {
                position: fixed;
                right: 10px;
                bottom: 10px;
                width: 200px;
            }
            & .submit {
                cursor: pointer;
                text-align: center;
                font-size: 20px;
                padding: 10px;
                background-color: #00E4A5;
                color: #fff;
                border-radius: 5px;
                box-shadow: 0 2px 10px 0 rgba(0,0,0,.13);
                border-bottom: 2px solid #00C791;
                text-shadow: 0px -1px 0px #009E73;
            }
        `);
    }

}

export default Transmit.createContainer(Registration);

3条回答
你好瞎i
2楼-- · 2019-03-26 08:13

edit

If you're going to follow the pattern of binding in the constructor, make sure you use a correct constructor invocation:

constructor (props) {
    super(props)

Notice props inside the constructor.

original answer

Since it appears you're using ES6 component definitions, you should bind to this within the rendered component:

<input type="text" value={this.state.name} onChange={this.onChangeName.bind(this)} />

You don't need to define this stuff in the constructor:

 //this doesn't work
 //this.onChangeName = this.onChangeName.bind(this);
 //this.onChangePassword = this.onChangePassword.bind(this);

It also appears that maybe you've left out some code in your example, so I'm not sure if you were trying to get rid of the unnecessary parts for the sake of example or what, but make sure your component is properly structured.

查看更多
兄弟一词,经得起流年.
3楼-- · 2019-03-26 08:16

If you use an arrow function then you won't need to bind.

onNameChange = (e)=> {
this.setState({name:e.target.value});
}

onPasswordChange = (e) => {
this.setState({password:e.target.value});
}
查看更多
ゆ 、 Hurt°
4楼-- · 2019-03-26 08:23

In these event handlers, e.target is the <input> which triggered the event.

onChangeName(e) {
    //this.state.name = e.target.name
    this.setState({ name: e.target.name});
}

onChangePassword(e) {
    //this.state.password = e.target.name
    this.setState({ password: e.target.password });
}

You get an input's value by using its value property:

onChangeName(e) {
    this.setState({name: e.target.value});
}

onChangePassword(e) {
    this.setState({password: e.target.value});
}

You also need to ensure this is bound properly, as per the commented-out code in your constructor.


If you give your inputs suitable name props, you replace these with a single onChange handler:

constructor(props) {
  super(props)
  // ...
  this.onChange = this.onChange.bind(this)
}

onChange(e) {
  this.setState([e.target.name]: e.target.value})
}

render() {
  // ...
  <input type="text" name="name" value={this.state.name} onChange={this.onChange}/>
  <input type="password" name="password" value={this.state.password} onChange={this.onChange}/>
  // ...
}
查看更多
登录 后发表回答