Why isn’t the concat() working in react/hook?

const [user, setUser] = useState([]);

  const onClick = () => {
    const octokit = new Octokit({
      headers: {
        accept: "application/vnd.github.v3+json",
        authorization: `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`,
      },
    });
    const response = octokit.request(`GET /orgs/{org}/repos`, {
      org: "octokit",
      type: "public",
    });
    response //
      .then((res) =>
        res.data.map((data) => {
          const info = user.concat({
            name: data.full_name,
            id: data.id,
            avatar: data.owner.avatar_url,
          });
          setUser(info);
          console.log(user);
        })
      );
  };

Why is it only the last value written as above?

Below is the result when pressed.

enter image description here

Answer

The “set” operation is asynchronous, so each iteration of map() is seeing the same value of user and queueing its own call to setUser. When the thread is available, all of the asynchronous setUser operations are performed, and each one concats one element to an empty array. So whichever is performed last will be the remaining value of user.

If res.data contains an array that should be mapped to the user value, perform the mapping first and then set the complete result. Perhaps something like this:

const info = res.data.map((data) => ({
    name: data.full_name,
    id: data.id,
    avatar: data.owner.avatar_url,
}));
setUser(info);

Semantically you shouldn’t be using map like a “loop” the way you are anyway. map is for projecting a collection into another collection of the same length, not for iterating over elements and performing an operation.

While we’re talking semantics, variable names like “user” imply only a single instance where yours is an array. And variable names like “info” imply nothing useful at all. Some quick renaming makes the code much more clear:

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

// later...
const updatedUsers = res.data.map(u => ({
    name: u.full_name,
    id: u.id,
    avatar: u.owner.avatar_url,
}));
setUsers(updatedUsers);