【備忘録】useEffect の中で即時関数を使う
はじめに
.then
を使うのが良くないと聞いたので、useEffect
内で非同期処理を行う方法について調べた備忘録です。
勉強したてで調べながらなので、間違っているところがあれば教えていただけると幸いです。
即時関数を使う理由
即時関数は、関数を定義すると同時に実行する書き方。
よくasync
を組み合わせて、非同期処理を簡潔に書くために使われる。
なぜ使うのか?
await
をトップレベルで使えない
1. 通常のスクリプトのトップレベルではawait
は使えない。
// これはエラーになる
await fetchData();
でも、即時関数を使えば await を使える。
(async () => {
const data = await fetchData();
console.log(data);
})();
2. スコープを汚さない
即時関数内で変数を定義すると、その変数は関数スコープ内に閉じ込められるので、グローバルスコープを汚さない。
(() => {
const secret = "これは外から見えない";
console.log(secret);
})();
console.log(secret); // ❌ エラーになる
async
関数をすぐに実行できる
3. async function
を定義してから実行するのではなく、即時関数を使えば関数を定義しつつ即実行できる。
(async () => {
const response = await fetch("https://api.example.com");
const data = await response.json();
console.log(data);
})();
これなら.then
を使わずに非同期処理を書ける。
.then
を避ける理由
.then
はネストが深くなってしまいがちで、可読性が落ちることがある。
fetch("https://api.example.com")
.then(response => response.json())
.then(data => {
console.log(data);
})
.catch(error => console.error(error));
これは.then
が続いてしまい、処理の流れがわかりにくくなる。
解決策 → async/await
async/await
を使うと、同期的なコードのように書けるので可読性が上がる。
async function fetchData() {
try {
const response = await fetch("https://api.example.com");
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}
fetchData();
ただし、この方法だと fetchData() を別途呼び出さないといけない。
これを省略したい場合は 即時関数を使う。
(async () => {
try {
const response = await fetch("https://api.example.com");
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
})();
使用例
このカスタムフックuseThreads
は、掲示板のスレッド一覧を取得し、React のuseState
を使って管理します。
コンポーネントがマウントされたタイミングでデータを取得し、threads
に格納します。
修正前
以下のコードでは、fetch
を.then()
チェーンで扱っています。
import { useEffect, useState } from "react";
export function useThreads() {
const [threads, setThreads] = useState([]);
useEffect(() => {
fetch("/threads")
.then((response) => response.json())
.then((data) => {
setThreads(data);
});
}, []);
return { threads };
}
修正後
async/await
を使うことで、非同期処理の可読性を向上させました。
データ取得をuseEffect
の中で即時実行関数(async () => { ... })();
にラップすることで、従来の.then()
よりもシンプルに記述できたかと思います。
import { useEffect, useState } from "react";
export function useThreads() {
const [threads, setThreads] = useState([]);
useEffect(() => {
(async () => {
const url = "/threads";
const response = await fetch(url);
const data = await response.json();
setThreads(data);
})();
}, []);
return { threads };
}
まとめ
- 即時関数は関数を定義すると同時に実行できる
-
await
はトップレベルで使えないので、即時関数を使うと便利 -
.then
はネストが深くなりやすいので、async/await
を使うと可読性が上がる - 即時関数を使うと、関数を定義せずに
async/await
を活用できる
Discussion