Reputation: 7628
I am relative new to React and I am building an new application with it. My main problem now is that I have a state with some properties. based on onchange
attributes I change the state properties. After that, when I am submitting the form, I try to assign a object to one specific property from the state, which I'll recieve from a find
method on an array.
So I have a state. I make a copy of this. After that, I do the find
method and store that object I got from it in a variable. Then I'll assign that object to a specific property (icecream) from my state. At the end I set the state with my new state (NewState).
The main problem is that after submitting the form the property (icecream) I assigned the object to is returning null. Really weird, because if I do a console.log
with just the variable of the newState variable it is returning an object instead of null. When I console.log
the state it is returning null, and so, the form will also be submitted with the property of null. My React dev tools says that the property (icecream) is actually filled and not null.
My Code
constructor(props) {
super(props);
this.state = {
Order: {
quantity: null,
name: '',
email: '',
icecream_id: 1,
icecream: null
}
}
this.handleSubmit = this.handleSubmit.bind(this);
this.handleInput = this.handleInput.bind(this);
this.getIcecream = this.getIcecream.bind(this);
}
handleInput(key, e) {
//Get a copy of the current state
var state = Object.assign({}, this.state.Order);
//apply for each key the new value
state[key] = e.target.value;
//Set the state by the new changes
this.setState({ Order: state });
}
getIcecream(e) {
e.preventDefault();
//Get another copy of the new state
var newState = Object.assign({}, this.state.Order);
///Find the icecream object based on the selected icecream
var object = this.props.icecreams.find((item) => item.id == this.state.Order.icecream_id);
//Set the icecream with the founded object
newState.icecream = object;
//Set the new state
this.setState({ Order: newState });
console.log(newState);
console.log(this.state.Order);
}
handleSubmit() {
if (isNaN(this.state.Order.quantity)) {
alert('Quantity is not a number');
} else {
this.props.addOrder(this.state.Order);
this.setState({ Order: { name: '', email: '', quantity: 0, icecream_id: 0, icecream: null } });
//this will work for now
this.props.history.push('/home/orders');
}
}
HTML/JSX
<form onSubmit={this.getIcecream}>
<div className="card card-default">
<div className="card-header">Add a custom order</div>
<div className="card-body table-responsive">
<div className="form-row">
<div className="col">
<label>Name customer</label>
<input type="text" className="form-control" placeholder="Name customer" onChange={(e) => this.handleInput('name', e)} required />
</div>
<div className="col">
<label>E-mail customer</label>
<input type="email" className="form-control" placeholder="E-mail customer" onChange={(e) => this.handleInput('email', e)} required />
</div>
</div>
<div className="form-row mt-3">
<div className="col">
<label>Quantity (liters)</label>
<input type="number" className="form-control" placeholder="1" min="1" onChange={(e) => this.handleInput('quantity', e)} required />
</div>
<div className="col">
<label>Select icecream</label>
<select className="form-control" value={this.state.Order.icecream_id} onChange={(e) => this.handleInput('icecream_id', e)}>
{this.props.icecreams.map((item) => {
return <option value={item.id} key={item.id}>{item.title} ({item.id})</option>
})}
</select>
</div>
</div>
</div>
</div>
<button type="submit" className="custom-button mt-20">Add order</button>
</form>
Console.log
Is there something I am missing?
Upvotes: 5
Views: 14278
Reputation: 1337
The function setState is asynchronous. If you don't know what that means, basically it ask js to do something, but we don't really know when this will be done. However, js still runs the next portions of code. So when you are doing this
this.setState({ Order: newState });
console.log(newState);
console.log(this.state.Order);
this.state.Order haven't changed yet. However, setState is overloaded and you can call it with 2 arguments like this
this.setState({ Order: newState },
()=>{console.log(this.state.Order}
);
This makes sure the console log is done after the setState.
Upvotes: 13