Reputation: 565
I'm looping thru a teams array getting team data and players for each team...
I have 2 async functions that pull the same data but I can't figure out how to combine them.
As it works currently, each loop adds the teamPlayers array to a players array in the first async function. On completion I have 1450 player objects in my players array. The second async function adds the team object to a teams array. On completion I have 32 team objects in my teams array.
I've tried changing the first async function to get data and then have the dispatch return a value of results.teamPlayers but I end up with a players array with 32 arrays each with x number of player objects.
async function loadRosters(endPoints, teams, authKey) {
axios.defaults.headers.common['Authorization'] = authKey;
const requests = teams.map(teamId => {
try {
return axios.get(endPoints.roster + teamId).then(r => r.data.teamPlayers);
} catch (e) {
console.log(e);
}
return [];
});
const results = (await Promise.all(requests)).flat();
dispatch({ type: 'SET_PLAYERS', value: results });
return results;
}
async function loadTeamData(endPoints, teams, authKey) {
axios.defaults.headers.common['Authorization'] = authKey;
const requests = teams.map(teamId => {
try {
return axios.get(endPoints.roster + teamId).then(r => r.data.team);
} catch (e) {
//
}
return [];
});
const results = (await Promise.all(requests)).flat();
dispatch({ type: 'SET_TEAM_LOGOS', value: results });
return results;
}
Here is the structure of the data I'm getting:
{
"team": {
"teamId": "string",
"abbr": "string",
"logo": "string"
},
"teamPlayers": [
{
"firstName": "string",
"lastName": "string",
"esbId": "string",
"position": "string",
"jerseyNumber": 0,
"teamAbbr": "string",
"headshot": "string"
}
]
}
It may be simpler if I get the team.logo and add it to each player in teamPlayers.
Upvotes: 1
Views: 888
Reputation: 565
I figured it out but please tell me if you think there is a more efficient solution.
async function loadRosters(endPoints, teams, authKey) {
axios.defaults.headers.common['Authorization'] = authKey;
const requests = teams.map(teamId => {
try {
return axios.get(endPoints.roster + teamId).then(r => r.data);
} catch (e) {
//
}
return [];
});
const results = (await Promise.all(requests)).flat();
dispatch({ type: 'SET_PLAYERS', value: results.map(r => r.teamPlayers).flat(Infinity) });
dispatch({ type: 'SET_TEAM_LOGOS', value: results.map(r => r.team) });
return results;
}
Upvotes: 0
Reputation: 78840
To avoid fetching the same team multiple times, you could cache your results. For example, if this is a redux store, you could dispatch teams and place them in your redux state. To put it all together, you can write an async function that either retrieves teams from the store or fetches if it hasn't yet been fetched.
// Not sure how you are getting "dispatch" earlier, but assuming you've got a getState as well...
const inProgress = new Map();
async function loadTeam(endPoints, teamId, authKey) {
const { teams } = getState();
if (teamId in teams) {
return teams[teamId];
}
let promise = inProgress.get(teamId);
if (!promise) {
axios.defaults.headers.common['Authorization'] = authKey;
promise = axios.get(endPoints.roster + teamId);
inProgress.set(teamId, promise);
}
const { data: team } = await promise;
inProgress.delete(teamId);
// TODO: add a reducer that puts this team in your state
dispatch({ type: 'SET_TEAM', payload: { teamId, team } });
return team;
}
Now you don't have to worry about duplicate fetches if you use this loadTeam
function:
async function loadRosters(endPoints, teams, authKey) {
axios.defaults.headers.common['Authorization'] = authKey;
const requests = teams.map(teamId => loadTeam(endPoints, teamId, authKey));
const results = (await Promise.all(requests))
.map(team => team.teamPlayers)
.flat();
dispatch({ type: 'SET_PLAYERS', value: results });
return results;
}
Upvotes: 0
Reputation: 1905
Just as a suggestion, why don't you create an endpoint that accepts multiple team IDs so you don't need to send multiple requests to the server, it can return all the data at once in an array? Also, having both a team
and a teamPlayers
key returning from that endpoint is slightly dubious design, at least semantically. Anyway, here's my best attempt:
async function loadTeams(endPoints, teams, authKey) {
axios.defaults.headers.common['Authorization'] = authKey;
const requests = teams.map(teamId =>
axios.get(endPoints.roster + teamId).then(res => res.data, e => {
console.error(e);
return { teamPlayers: [], team: [] };
})
);
const allTeamData = await Promise.all(requests);
// Following variables will aggregate ALL players from ALL teams and
// ALL logos (? it seems your logos are arrays, but that's a bit weird)
const allTeamPlayers = [], allTeamLogos = [];
for (const { teamPlayers, team } of allTeamData) {
allTeamPlayers.push(...teamPlayers); // spread optional
allTeamLogos.push(...team); // again, spread optional
}
dispatch({ type: 'SET_PLAYERS', value: allTeamPlayers });
dispatch({ type: 'SET_TEAM_LOGOS', value: allTeamLogos });
return { teamPlayers: allTeamPlayers, team: allTeamLogos };
}
Now you can call the function and get the teamPlayers
or team
keys of the result to get whatever you need.
Upvotes: 3