1
function App() {
  const [name, setName] = useState('');
  
  // *****************
  const onNameChange = (e) => {
    setName(e.target.value)
    console.log(name)   
    
  }

  const onSubmit = (e) => {
    e.preventDefault();
    setName('')
  }

  return (
    <div className="App">

      <form onSubmit={onSubmit}>
        <input type="text" value={name} onChange={onNameChange} />
        <button>submit</button>
      </form>

    </div>
  )
}
export default App;

why i'm not able to log complete name in console? for example: if i fill "amit" in the form the log will be like this:

  1. when type "a" console is blank
  2. when type "am" console is "a"
  3. when type "ami" console is "am"
  4. when type "amit" console is "ami"

why the output is one character less? Is setName is async? if Yes then why async/await doesn't have any effect on it?

NOTE: the same logic in Class Component works fine.

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
  • 1
    It is async, but even then, `name` is a `const` in this scope, so it's never going to change, whatever you do within the function, until the component is rendered again. – Emile Bergeron Jul 13 '20 at 17:58

2 Answers2

1

You're console logging the old value; add a useEffect to console log the new value:

  useEffect(()=> {
    console.log(name)   
  }, [name])

The same logic does not work fine in a class component (see code snippet). The console log still responds with the old state if called from the handler; you would have to console log within componentDidUpdate for the new result.

class App extends React.Component {
  state = { name: "" };
  // *****************
  onNameChange = e => {
    this.setState({ name: e.target.value });
    console.log("onNameChange:", this.state.name);
  };

  componentDidUpdate() {
    console.log("componentDidUpdate:", this.state.name);
  }

  onSubmit = e => {
    e.preventDefault();
  };

  render() {
    return (
      <div className="App">
        <form onSubmit={this.onSubmit}>
          <input
            type="text"
            value={this.state.name}
            onChange={this.onNameChange}
          />
          <button>submit</button>
        </form>
      </div>
    );
  }
}

ReactDOM.render(<App/>, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Pavlos Karalis
  • 2,893
  • 1
  • 6
  • 14
0

Just like setState in Class components created by extending React.Component, the state update using the updater provided by useState hook in functions is also asynchronous, and will not immediately reflect. You cant use await useState() because it is assumed to be unchanging during 1 render. Read more

You can simply fix this by reading the value in render function (not inside nested functions), or do something like this:

 useEffect(()=> {
    console.log(name)   
  }, [name])
Dani
  • 556
  • 7
  • 23