users array hook is not updating with all the list items

Viewed 38

So I'm creating a simple MERN App, backend is working properly, but when working with useState hook in frontend is causing issues. what im trying to do is to fetch "users" data(an array of object with field username) from backend endpoints, and updating the users array which is a hook, but it only updates with the last itm of the incoming username and not list of all usernames!!

code for fetching and updating the hook:

const [users, setUsers] = useState([]);

const getUsers = () => {
    fetch("http://localhost:5000/users")
        .then(res => res.json())
        .then(data => {
            console.log(data);      //line 17
            data.map((itm) => {
                console.log([itm.username])      //line 19
                setUsers([...users, itm.username])
            })
        })
        .catch(err => console.log(err))
}

useEffect(() => {
    getUsers();
}, [])

console.log(users);       //line 30

what I want is to get a list of usernames in the "users" state! something like this: users = ["spidey", "thor", "ironman", "captain america"]

console.log is also not showing any errors... console window

pls help, can't figure out where it's getting wrong?

2 Answers

The issue is two-fold, first you are using Array.prototype.map to iterate an array but are issuing unintentional side-effects (the state updates), and second, you are enqueueing state updates in a loop but using standard updates, each subsequent update overwrites the previous so only the last enqueued update is what you see in the next render.

Use either a .forEach to loop over the data and use a functional state update to correctly update from the previous state.

const getUsers = () => {
  fetch("http://localhost:5000/users")
    .then(res => res.json())
    .then(data => {
      console.log(data);
      data.forEach((itm) => {
        console.log([itm.username]);
        setUsers(users => [...users, itm.username]);
      })
    })
    .catch(err => console.log(err));
}

Or use the .map and just map data to the array you want to append to the users state.

const getUsers = () => {
  fetch("http://localhost:5000/users")
    .then(res => res.json())
    .then(data => {
      console.log(data);
      setUsers(users => users.concat(data.map(itm => itm.username)));
    })
    .catch(err => console.log(err));
}

you can set the map result in a variable after that you can call the useState on it.

 const [users, setUsers] = useState([]);

 const getUsers = () => {
   fetch("http://localhost:5000/users")
    .then(res => res.json())
    .then(data => {
        console.log(data);      //line 17
        const userNameData = data.map(itm => itm.username)
     setUsers(...users, userNameData)
    })
    .catch(err => console.log(err))
  }

 useEffect(() => {
   getUsers();
 }, [])

 console.log(users);
Related