Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

console log the state after using useState doesn't return the current value

using console.log() after using reactjs useState() hook, doesn't return the current value of this state, How can I handle this?

Here's code for the case, try to figure out what's the console log display.

import React, { useState } from "react";
import ReactDOM from "react-dom";

function Weather() {
  const [weather, setWeather] = useState();

  return (
    <input
      value={weather}
      onChange={(e) => {
        setWeather(e.target.value);
        console.log(weather);
      }}
    />
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Weather />, rootElement);
like image 811
Zeyad Etman Avatar asked Feb 25 '19 13:02

Zeyad Etman


People also ask

Why React setState useState does not update immediately?

The answer: They're just queues setState , and React. useState create queues for React core to update the state object of a React component. So the process to update React state is asynchronous for performance reasons. That's why changes don't feel immediate.

Does useState return anything?

What does useState return? It returns a pair of values: the current state and a function that updates it. This is why we write const [count, setCount] = useState() . This is similar to this.state.count and this.setState in a class, except you get them in a pair.

Does useState hook update immediately?

PureComponent , the state update using the updater provided by useState hook is also asynchronous, and will not be reflected immediately.

What are the return values of the useState function?

We initialize our state by calling useState in our function component. useState accepts an initial state and returns two values: The current state. A function that updates the state.


Video Answer


3 Answers

useState by default simply does one thing and one thing only, set the new state and cause a re-render of the function. It is asynchronous in nature so by default, methods running after it usually run.

From your example, on a fresh load of the page, typing 's' causes useState to change the state, but because it is asynchronous, console.log will be called with the old state value, i.e. undefined (since you didn't set a value. You should consider setting an initial state, if you want to)

const [weather, setWeather] = useState('');    // Set the intial state

The only way to truly read the value of the state is to use useEffect, which is called when there is a re-render of the component. Your method simply becomes:

import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom';

function Weather() {
    const [weather, setWeather] = useState('');

    useEffect(() => console.log(weather), [weather]);

    const changeValue = event => setWeather(event.target.value);

    return <input value={weather} onChange={changeValue} />;
}

const rootElement = document.getElementById('root');
ReactDOM.render(<Weather />, rootElement);
like image 104
cr05s19xx Avatar answered Oct 11 '22 00:10

cr05s19xx


When you call setWeather, you trigger a rerender of your component, which will call again this function. However, the console.log(weather); inside the function still references the first value returned by useState, which is your orignal value. If you want to print it you should be doing :

console.log(e.target.value);
like image 31
Vinz243 Avatar answered Oct 10 '22 23:10

Vinz243


onChange={(e) => {
    setWeather(e.target.value);
    console.log(weather);
  }}

when this function is fired, since setWeather is async, it will be passed to web api. Javascript engine does not handle this function. wep api handles this and when it is done event loop which is part of the web api pass this to the call stack.

call stack is where functions get executed. once async functions are passed to the web api, regardless of its executing time (even though it has 0 second time out), they will not moved to call stack unless javascript engine finishes the execution of sync code. once call stack is free, event loop will pass the function to call stack to be executed.

So in your code, onChange() is passed to call stack. Inside of this function, 2 functions have to be executed. since setWeather is async, it goes to web api, gets the e.target.value, meanwhile console.log gets executed. when there is no sync code left in the call stack, event loop pushes the setWeather to the call stack to be executed.

Let's say you enter "name" to the input field. after "nam", state is "nam", but when you type "e", this will be executed in webapi, so while it is in web api, console.log will log the current state which is "nam". that is why you will always see the console one character behind

like image 3
Yilmaz Avatar answered Oct 10 '22 23:10

Yilmaz