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);
The "cannot read property 'setState' of undefined" error occurs when a class method is called without having the correct context bound to the this keyword. To solve the error, define the class method as an arrow function or use the bind method in the classes' constructor method.
The render() function should be pure, meaning that it does not modify a component's state. It returns the same result each time it's invoked, and it does not directly interact with the browser. In this case, avoid using setState() here.
The "cannot read property 'map' of undefined" error occurs when we call the map() method on an undefined value, most often when the map method is called before the data from an API request has arrived. To solve the error, initialize the value you're mapping over to an empty array.
setState is asynchronous call means if synchronous call get called it may not get updated at right time like to know current value of object after update using setState it may not get give current updated value on console. To get some behavior of synchronous need to pass function instead of object to setState.
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.
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.
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}/>
// ...
}
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});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With