Giesburts
Giesburts

Reputation: 7628

ReactJS - State object property is null after setState

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

enter image description here

Is there something I am missing?

Upvotes: 5

Views: 14278

Answers (1)

Kerry Gougeon
Kerry Gougeon

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

Related Questions