1

I'm new to React and I want to update the state of an object when the input changes its value.

I've searched some references relating to this and there are several solutions, like this. However, it doesn't work correctly for me.

Applied this solution, I get the value incorrectly. For example, I type the input value: "name", but the value I get is only "nam". The last character is missing.

What's wrong here? Anyone here can help me? Thank you in advanced.

Here is my code for component AddHero.js

import React, { Component } from 'react';

class AddHero extends Component {

constructor(props) {
    super(props);

    this.state = {
        hero: {}
    };

    this.addHero = this.addHero.bind(this);
    this.nameChange = this.nameChange.bind(this);      
}

addHero() {

}

nameChange(event) {
    var temp = {...this.state.hero};
    temp.Name = event.target.value;   
    this.setState({hero:temp});

    console.log(this.state.hero.Name);//the value of Name is always missing the last character from the input
}   

render() {
    return (
        <div>
            <div className="name">
                <label>Name: </label>
                <input type="text" id="Name" onChange={this.nameChange} />
                {/* <p class="alert alert-danger invalid" >Invalid Name</p> */}
            </div>

            <div className="submit">
                <button type="button" onClick={this.addHero} >Add new</button>
            </div>
        </div>
    );
}
}

export default AddHero;

Here is the snapshot:

enter image description here

anhtv13
  • 1,636
  • 4
  • 30
  • 51
  • `setState()` is asynchronous, you can't `console.log` on the next line and expect change to be there – Jayce444 Nov 02 '18 at 02:25
  • Put console.log into render and check it will work, setstate is async – Just code Nov 02 '18 at 02:26
  • side note: instead of doing `.bind` in the constructor you could just change: `nameChange(event) {` to `nameChange = (event) => {` – BrunoLM Nov 02 '18 at 02:38
  • @BrunoLM if I remove ".bind" in the constructor, when I call "this.state..." in the function nameChange(event), "this" will be undefined. – anhtv13 Nov 02 '18 at 02:45
  • Possible duplicate of [Why calling react setState method doesn't mutate the state immediately?](https://stackoverflow.com/questions/30782948/why-calling-react-setstate-method-doesnt-mutate-the-state-immediately) – Alexander Staroselsky Nov 02 '18 at 04:17

4 Answers4

2

The setState method doesn't change the state of the component immediatly. One solution to your problem however, is to make use of the setState() method's callback (which gets called when the state change has taken effect).

Consider the following which shows how you can log the state of your component, after the state change has taken effect:

nameChange(event) {
    var temp = {...this.state.hero};
    temp.Name = event.target.value;   

    this.setState({hero:temp}, 
    () => { // Callback called when state change has been applied

       // Prints the latest state for hero.name
       console.log(this.state.hero.Name);
    });
}  
Dacre Denny
  • 29,664
  • 5
  • 45
  • 65
1

It is pretty simple. When you run console.log(this.state.hero.Name); your state has not changed yet since this.setState() is async call. It means that everything what happens after its execution does not have an access to update state yet... To fix that you log console.log(temp); since it is an object you are going to use to update your this.state.hero

OR

you can use a callback for setState to get access to your state AFTER the async call finished its execution. Here is one of good articles about it setState callback

anvk
  • 1,183
  • 8
  • 10
1

Likethis:

 this.setState(currentState => ({ count: currentState.count + 1 }), () => {
    console.log(this.state.count);
});
Orgil
  • 251
  • 4
  • 19
1

Whenever you need to update the state based on a previous state you have to use the updater argument

If you need to set the state based on the previous state, read about the updater argument below. https://reactjs.org/docs/react-component.html#setstate

Basically it is calling setState with a callback function

this.setState((state) => ({ hero: { ...state.hero, Name: 'foo' } }))
BrunoLM
  • 97,872
  • 84
  • 296
  • 452