I have app about hockey statistics, I dont have endpoint with this stats , I have endpoint with team and player stats. I am calling api with first team , select first 2 players save to arr and call api again with another team query, find top players from another team and save it .
Than sort topPlayers and display it.
When I open console.log() => NETWORK i can see API with specific team is called twice.
How to fix it?
const teamQuery = useMemo(() => {
return [
"NSH", "TBL", "PIT", "CHI", "VGK", "MIN", "ANA",
"FLA", "PHI", "WSH", "ARI", "NYI", "SJS", "CGY",
"BUF", "NYR", "CBJ", "NJD", "DET", "DAL",
"TOR", "MTL", "BOS", "LAK", "COL", "WPG",
"SEA", "CAR", "OTT", "EDM", "STL", "VAN"
];
}, []);
const fetchTeamData = async (teamQuery) => {
try {
const queryParam = encodeURIComponent(teamQuery);
const res = await axios.get(`/api/NHL/findTeam?team=${queryParam}`);
return res.data.data;
} catch (error) {
console.error(error);
return null;
}
};
const fetchAllTeamsData = useCallback(async () => {
setLoad(true);
const topPlayers = [];
for (const team of teamQuery) {
setClub(team);
const teamData = await fetchTeamData(team);
if (teamData && teamData.players) {
const sortedPlayers = teamData.players.sort((a, b) => b.stats.points - a.stats.points);
const teamTopPlayers = sortedPlayers.slice(0, 2);
topPlayers.push(...teamTopPlayers);
}
}
// sort players
const sortedTopPlayers = topPlayers.sort((a, b) => b.stats.points - a.stats.points);
setAllTopPlayers(sortedTopPlayers);
const sortedTopGoals = [...topPlayers].sort((a, b) => b.stats.goals - a.stats.goals);
setTopGoals(sortedTopGoals);
const sortedTopAssists = [...topPlayers].sort((a, b) => b.stats.asists - a.stats.asists);
setTopAssists(sortedTopAssists);
const sortedMostPIM = [...topPlayers].sort((a, b) => b.stats.penalty - a.stats.penalty);
setMostPIM(sortedMostPIM);
setLoad(false);
}, [teamQuery]);
useEffect(() => {
fetchAllTeamsData();
}, [fetchAllTeamsData]);
2
Answers
1 – You began by declaring a
teamQuery
usinguseMemo()
. This is fine as it improves performance by memorising the array and recreating it only when the dependency array changes. Here, the dependency array is empty which means the array never changes.2 – Then you declared
fetchAllTeamsData
usinguseCallback()
. This hook returns a memoized version of the callback function that only changes if one of the dependencies has changed. In this case, teamQuery is the only dependency.3 – Lastly, you introduced an effect via
useEffect()
, callingfetchAllTeamsDat
a wheneverfetchAllTeamsData
itself changes. This creates a circular effect: whenfetchAllTeamsData
runs, it changes its own reference, causing the effect to be re-run.4 – To solve this issue, you can move the
teamQuery
array outside of the component or simply define it as a constant inside the component, removing the need foruseMemo()
anduseCallback()
. This way, it won’t trigger unnecessary re-renders or re-calls of your function.Read this: https://react.dev/reference/react/StrictMode
It‘s a feature, not a bug! This will be go away in Production.