はじめに
前ステップから続き、勉強用のuseFetchを書いていきます。今回のテーマはキャンセル処理です。
課題
URLを変更すると、クリーンアップ処理が走り、新しいデータ取得が走りますが、ブラウザが処理をしている前のデータ取得の処理を止めることができたわけではありません。例えば、長いデータを転送中だったり、サーバからの応答を待っていたり、サーバの名前解決をしていたりする場合は、データ取得の処理は継続しています。fetchはpromiseベースのAPIですが、AbortControllerを使うことで処理をキャンセル(abort)することができます。
ステップ5: キャンセル処理
const useFetch = url => {
const [result, setResult] = useState({});
useEffect(() => {
let cleanedUp = false;
const abortController = new AbortController();
const fetchData = async () => {
try {
const response = await fetch(url, {
signal: abortController.signal
});
if (!response.ok) throw new Error(`status: ${response.status}`);
const data = await response.json();
if (!cleanedUp) {
setResult({ data });
}
} catch (error) {
if (!cleanedUp) {
setResult({ error });
}
}
};
setResult({ loading: true });
fetchData();
const cleanup = () => {
cleanedUp = true;
abortController.abort();
setResult({});
};
return cleanup;
}, [url]);
return result;
};
念のため、cleanupでresultも初期化するようにしました。(一瞬以前のresultで描画されるを防ぐため)
動作確認
実際に動くコードはこちらです。codesandbox
キャンセルの動作はUIで直接は分かりませんので、Chrome DevToolsでNetworkタブを確認してください。
このように、ローディング中にURLを変更すると、canceledとなっていることを確認できると思います。
おわりに
本コードは勉強用ですので、そのままでは使わないでください。(ちゃんとした実装はこちら)
さらなる課題と解決は次のステップへ。