[Solved] React useState set method not reflecting change immediately

Article Tarif Hossain

When we assigned an initial value to a state in the form of an array. The set method useState is not worked even with spread(...) or without spread operator. 

Here is the code:

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

const StateSelector = () => {
  const initialValue = [
    {
      category: "",
      photo: "",
      description: "",
      id: 0,
      name: "",
      rating: 0
    }
  ];

  const [movies, setMovies] = useState(initialValue);

  useEffect(() => {
    (async function() {
      try {
        //const response = await fetch(
        //`http://192.168.1.164:5000/movies/display`
        //);
        //const json = await response.json();
        //const result = json.data.result;
        const result = [
          {
            category: "cat1",
            description: "desc1",
            id: "1546514491119",
            name: "randomname2",
            photo: null,
            rating: "3"
          },
          {
            category: "cat2",
            description: "desc1",
            id: "1546837819818",
            name: "randomname1",
            rating: "5"
          }
        ];
        console.log(result);
        setMovies(result);
        console.log(movies);
      } catch (e) {
        console.error(e);
      }
    })();
  }, []);

  return <p>hello</p>;
};

const rootElement = document.getElementById("root");
ReactDOM.render(<StateSelector />, rootElement);

The setMovies(result) as well as setMovies(...result) is not worked. (Line no: 16) 

We expect the result variable to be pushed into the movies array.

React this.setState, and useState does not make changes directly to the state object.

React this.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.

Even if you add a setTimeout function, though the timeout will run after some time. The setTimeout will still use the value from its previous closure and not the updated one.

setMovies(result);
console.log(movies) // movies here will not be updated

Solution:

React.useState doesn’t have to accept the callback function that gets called after React state has actually been modified.

To perform side effects after the state has changed, you must use the React.useEffect hook.

useEffect(() => {
    // action on update of movies
}, [movies])

The  setMovies(result) will replace the value of the previous movie in the state with those available from the async request.

That hook function will only activate if the values in the list change.

However, if you want to merge the response with the previously existing values, you must use the callback syntax during the state update along with the correct use of spread syntax.

setMovies(prevMovies => ([...prevMovies, ...result]));