私は自分の小さなプロジェクトに取り組んでいましたが、デプロイの直前に、使用していた API のポリシーが変更され、API 呼び出しが 1 秒に 1 回に制限されました。これにより、エラーが発生しました(エラー429:要求が多すぎます)。私の回避策(axios はヘッダー prop の後に再試行しないため、失敗した場合に再度呼び出しを行う fetch API を使用して何らかの再帰関数を作成することでした)。だから、もともと私は以下のコードのブロックで終わった:
//recursive function to make an api call
const fetchCalls = useCallback((url, setState, retries = 4) => {
fetch(url)
.then((res) => {
// check if successful. If so, return the response transformed to json
if (res.ok) {
return res.json();
}
// else, return a call to fetchRetry if number of retries >0
if (retries > 0) {
return fetchCalls(url, setState, retries - 1);
} else {
throw new Error(res);
}
})
.then((data) => {
if (data !== undefined) {
setState(data);
Axios.all([
Axios.get(
`${api.sparklineBase}${setLowerCase(
data[0].name
)}/market_chart/range?vs_currency=${
userData.currency.code
}&from=${dayUNIX}&to=${currentUNIX}`
),
Axios.get(
`${api.sparklineBase}${setLowerCase(
data[0].name
)}/market_chart/range?vs_currency=${
userData.currency.code
}&from=${yearUNIX}&to=${currentUNIX}`
),
])
.then((ress) => {
setSparkline((prevState) => {
return [...prevState, ress[0].data];
});
setSparkline((prevState) => {
return [...prevState, ress[1].data];
});
})
.catch((errr) => {
console.log(errr);
});
}
// Do something with the response
})
.catch((error) => {
console.log(error);
});
}, [userData, setSparkline]);
useEffect(() => {
Axios.get(`${api.zoneBase}apiKey=${api.zoneKey}&include=useragent`)
.then((response) => {
setUserData(response.data);
//calling fetchCalls function below
fetchCalls( `${api.base}key=${api.key}&ids=${match.params.id}&convert=${response.data.currency.code}&interval=1d,7d,30d,365d`,
setCryptos
);
})
.catch((err) => {
console.log(err);
});
return () => {
setCryptos([]);
setSparkline([]);
};
}, [setCryptos, setSparkline, setUserData, match, fetchCalls, cryptos]);
明らかに、useEffect と useCallback の両方のいくつかの依存関係が実際の非同期状態の値であることを推測して、非常に多くの再レンダリングを引き起こしました。
fetchCall(useCallback なし)を useEffect にスローすることを決定し、私はこれで終わった:
//forgot to comment out this bit.
const fetchCalls = useCallback((url, setState, retries = 4) => {
fetch(url)
.then((res) => {
// check if successful. If so, return the response transformed to json
if (res.ok) {
return res.json();
}
// else, return a call to fetchRetry
if (retries > 0) {
return fetchCalls(url, setState, retries - 1);
} else {
throw new Error(res);
}
})
.then((data) => {
if (data !== undefined) {
setState(data);
}
// Do something with the response
})
.catch((error) => {
console.log(error);
});
}, []);
useEffect(() => {
Axios.get(`${api.zoneBase}apiKey=${api.zoneKey}&include=useragent`)
.then((response) => {
setUserData(response.data);
const fetchCalls = (url, setState, retries = 4) => {
fetch(url)
.then((res) => {
// check if successful. If so, return the response transformed to json
if (res.ok) {
return res.json();
}
// else, return a call to fetchRetry
if (retries > 0) {
return fetchCalls(url, setState, retries - 1);
} else {
throw new Error(res);
}
})
.then((data) => {
if (data !== undefined) {
setState(data);
Axios.all([
Axios.get(
`${api.sparklineBase}${setLowerCase(
data[0].name
)}/market_chart/range?vs_currency=${
response.data.currency.code
}&from=${dayUNIX}&to=${currentUNIX}`
),
Axios.get(
`${api.sparklineBase}${setLowerCase(
data[0].name
)}/market_chart/range?vs_currency=${
response.data.currency.code
}&from=${weekUNIX}&to=${currentUNIX}`
),
])
.then((ress) => {
setSparkline((prevState) => {
return [...prevState, ress[0].data];
});
setSparkline((prevState) => {
return [...prevState, ress[1].data];
});
})
.catch((errr) => {
console.log(errr);
});
}
// Do something with the response
})
.catch((error) => {
console.log(error);
});
};
fetchCalls(
`${api.base}key=${api.key}&ids=${match.params.id}&convert=${response.data.currency.code}&interval=1d,7d,30d,365d`,
setCryptos
);
})
.catch((err) => {
console.log(err);
});
return () => {
setCryptos([]);
setSparkline([]);
};
}, [setCryptos, setSparkline, setUserData, match, fetchCalls]);
上記のコードは、期待どおりに機能します。ただし、元の fetchCalls 関数 (useEffect の外側) をコメントアウトするのを忘れていたことに気付きませんでした。API 呼び出しに依存する 2 番目の API 呼び出しセットのみをコメントアウトしたためです。これをコメントアウトしようとすると、fetchCalls が定義されておらず、fetchCalls が不要な依存関係であるというエラーが発生するようになりました。
ただし、コードの 2 番目のブロックでは、useEffect の fetchCalls が、useEffect の fetchCalls 関数が行う API 呼び出しに依存する API 呼び出しの 2 番目のセットを運ぶものであることに注意してください。
なぜこのように機能するのかを知りたいだけです。なぜなら、すべてが奇妙に思えるからです。さらに、これに使用できるより受け入れられる回避策はありますか?