ReactのuseEffectでasync/awaitを使うベストプラクティスを初心者向けに解説
生徒
「先生、useEffectの中で非同期処理をしたいときに、async/awaitを使う方法がよくわからないんです。」
先生
「確かに、初心者が最初につまずきやすいポイントです。useEffectの引数に直接asyncをつけることはできないので、正しい書き方を知っておく必要がありますよ。」
生徒
「直接asyncが使えないんですか?それならどうすればいいんでしょうか?」
先生
「安心してください。内部に非同期関数を作って呼び出す方法や、即時実行関数を使う方法がベストプラクティスとされています。それでは順番に見ていきましょう。」
1. useEffectの中でasync/awaitをそのまま使えない理由
ReactのuseEffectフックは、副作用(サーバーからのデータ取得やタイマーのセットなど)を処理するために使われます。しかしuseEffectの引数に渡す関数は同期処理である必要があります。もし直接asyncをつけると、その関数はPromiseを返してしまい、Reactが想定していない挙動になるのです。
つまり「使えない」のではなく「書き方を工夫する必要がある」ということです。初心者の方でも理解しやすく言い換えると、useEffectに渡す関数は「普通の箱」でないといけないのに、asyncをつけると「特別な箱」に変わってしまうので合わなくなる、というイメージです。
2. useEffectでasync/awaitを使う基本パターン
一般的な解決方法は、useEffectの中で新しくasync関数を定義し、その関数をすぐに呼び出すというパターンです。
import React, { useEffect, useState } from "react";
function App() {
const [data, setData] = useState(null);
useEffect(() => {
async function fetchData() {
const res = await fetch("https://jsonplaceholder.typicode.com/posts/1");
const json = await res.json();
setData(json);
}
fetchData();
}, []);
return (
<div>
<h1>記事タイトル</h1>
{data ? <p>{data.title}</p> : <p>読み込み中...</p>}
</div>
);
}
export default App;
3. 即時実行関数を使う書き方
もう一つの方法は、(async () => { ... })()という書き方です。これは「その場で作ってその場で実行する非同期関数」で、シンプルに書きたい場合によく使われます。
useEffect(() => {
(async () => {
const res = await fetch("https://jsonplaceholder.typicode.com/posts/2");
const json = await res.json();
setData(json);
})();
}, []);
この書き方は短くまとめられる反面、慣れないと読みづらいと感じるかもしれません。初心者の方はまず前の「async関数を定義して呼び出す方法」から練習すると理解しやすいです。
4. 非同期処理のキャンセルとエラーハンドリング
非同期処理は必ず成功するとは限りません。通信が失敗することもありますし、ユーザーが画面を切り替えたときに処理を止める必要もあります。そのためtry...catchを使ったエラーハンドリングや、AbortControllerを使ったキャンセル処理を組み合わせるのが実践的です。
例えば、記事の一覧を取得している途中で画面を離れたときに不要な更新が走らないようにできます。これにより「アンマウントされたコンポーネントに更新をしようとしてエラーになる」といったトラブルを防げます。
5. 初心者が覚えておきたいポイント
useEffectの中でasync/awaitを使うときに大切なのは以下の3点です。
- 直接useEffectの引数にasyncは書けない
- 中でasync関数を作って呼び出すか、即時実行関数を使う
- エラー処理やキャンセル処理も忘れずに入れると安全
これらを押さえておけば、Reactの非同期処理を安心して扱えるようになります。プログラミング未経験の方でも「箱の中にasyncを隠して使う」というイメージを持つと理解しやすいです。