Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

State not updating from useEffect hook

For some reason when I am updating my state from the useEffect hook it is not persisting. I am expecting that my list of users will keep growing, but instead I am only seeing one user. Why is users not growing?

import { useState, useEffect } from "react";

interface IUser {
  name: {
    first: string;
    last: string;
  };
  picture: {
    thumbnail: string;
  };
}

function App() {
  const [users, setUsers] = useState<IUser[]>([]);

  const getUserName = (user: IUser): string => {
    if (!user) return "";

    return `${user.name.first} ${user.name.last}`;
  };

  const getThumbnail = (user: IUser): string => {
    if (!user) return "";

    return user.picture.thumbnail;
  };

  useEffect(() => {
    setInterval(() => {
      fetch("https://randomuser.me/api")
        .then((res) => res.json())
        .then((json) => {
          let newusers = [...users, json.results[0]];
          setUsers(newusers);
        })
        .catch((err) => {
          console.log(err);
        });
    }, 3000);
  }, []);

  return (
    <div className="App">
      {users?.map((user, idx) => (
        <div key={idx}>
          <h2>{getUserName(user)}</h2>
          <img src={getThumbnail(user)} />
        </div>
      ))}
    </div>
  );
}

export default App;

Here is a codesandbox demonstrating the issue https://codesandbox.io/s/react-typescript-forked-5h3553?file=/src/App.tsx:0-1054

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

The problem comes from the use of setInterval. When it is defined, it creates a closure including the current value of the variable users which of course starts as []. So every time the interval is invoked, it is using the value it had at the time of instantiation.

Luckily, calls to setState pass a parameter of the previous state, which you can use to quickly fix your problem:

.then((json) => {
  setUsers((prev) => [...prev, json.results[0]]);
})
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading