Loop over an array of ids and make a separate request each time

Viewed 399

I have an api endpoint such as this and I need to make a put request to this endpoint.

   api/user-group/{id}/invite/{userId}

The problem i'm having is my form contains a multi-list, react select list that allows users to select as many groups as they want and so everytime a user selects a group I'm storing the groups id in local state but my api endpoint only takes in one group id. The solution I think is too loop over the group ids and do separate requests. Can someone guide me on how to achieve this solution or is there a better solution?

My Code:

    const AddUserToGroupPage = () => {
       const [currentUserId, setCurrentUserId] = useState('');
       const [GroupIds, setGroupIds] = useState([]); 

       const { inviteUserToGroup } = useUserGroupApi();


      const InviteExistingUser = async () => {
        const body = {};
        const res = await inviteUserToGroup({
          id: groupIds,
          body,
          userId: currentUserId,
        });
        return res;
      };

      const onGroupsSelected = (selected) => {
        if (selected) {
          setGroupIds(selected.map((select) => select.value));
        }
      };

      return (
            <>
              <Select
                name="userGroups"
                label="User Groups"
                placeholder="Select as many groups as you want"
                id="userGroups"
                defaultOptions
                options={groups}
                isMulti
                onSelectChange={onGroupsSelected}
            />
         </>
)
    }
2 Answers

I think you can achieve what you want like this:

const InviteExistingUser = async () => {
    const body = {};
    return await Promise.all(
        groupIds.map((groupID) => {
            return inviteUserToGroup({
                body,
                id: groupID,
                userId: currentUserId,
            });
        }),
    );
};

In this code, the call to groupIds.map() will return a list of Promises that each resolve to the return value from a call to inviteUserToGroup (one result for each group ID).

Then you can pass that list to Promise.all, which returns a Promise that resolves to a list of results. So basically you go from Promise<result>[] (a list of promises) to Promise<result[]> (a promise for a list).

Then you can await that Promise, at which point you end up with a list of results for all the calls to inviteUserToGroup.

You have 3 options:

1. fire a single request each time

GroupIds.forEach(g => {
  const body = {};
  const res = await inviteUserToGroup({
    id: g.id,
    body,
    userId: currentUserId,
  });
  // save response
  setGroupsInfo(prev => [...prev, res]
})

2. fire all requests together

const requests = GroupIds.map(g => {
  return inviteUserToGroup({
    id: g.id,
    body,
    userId: currentUserId,
  });
})

Promise.all(requests).then(resArray => {
  setGroupsInfo(resArray)
})

3. fire a bunch (maybe 5) of request and wait until they ends and then fire more one and so on..

// take 5 each time
for(let i = 0; i < GroupIds.length; i += 5){
  const subGroupsIds = GroupIds.slice(i, i + 5);
  
  // fire 5 requests
  const requests = subGroupsIds.map(g => {
    return inviteUserToGroup({
      id: g.id,
      body,
      userId: currentUserId,
    });
  })

  // wait for the 5 requests
  const resArr = await Promise.all(requests);
  setGroupsInfo(prev => [...prev, ...resArr]);
}

the second option is the worst, since you could have so many groups and you can't request all of them in the same time.

the 3th option is the optimal one but it's implementation is not straight forward.

the first option is easy and but on large number of groups will be slow.

Related