Reactの勉強を進める中で「useEffect」という名前を見かけたけど、
「どんな場面で使えば良いのか」「何をしているのか」がイマイチわからない…。
そんな風に思っていませんか?
この記事では、ReactのuseEffectフックについて、
その基本的な使い方や特徴、そしてどういった場面で使うべきかを初心者の方でも理解しやすいように、
丁寧に解説していきます。
useEffectとは?
useEffectは、Reactが提供する「副作用(side effects)」を扱うためのフックです。
例えば、以下のような場面で利用します。
- データのフェッチ(APIからデータを取得するなど)
- DOMの更新(スクロール位置をリセットするなど)
- タイマーやインターバルの設定
- 外部のリソース(データベースやローカルストレージ)の変更や読み込み
副作用といきなり言われても意味わかりませんよね。
副作用は、簡単に言えば「コンポーネントのレンダリング以外で発生する処理」です。
Reactでは、UIの描画に必要な処理は原則render
メソッド内で行いますが、
それ以外の処理(副作用)はuseEffectで扱います。
とりあえず最初は、(side)Effectをuseするんだ、と覚えればいいでしょう。
(副)作用を使うから、useEffectってことね。
useEffectの基本的な書き方
まず、基本的な使い方を見てみましょう。
import { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
console.log("This runs after the component is rendered.");
});
return (
<div>
<p>My Component</p>
</div>
);
}
JSXこのように、useEffectの中に処理を入れると、コンポーネントがレンダリングされた後にその処理が実行されます。
useEffectの特徴
useEffectを使うときの特徴やポイントを解説します。
1. コンポーネントのライフサイクルに合わせた動作
useEffectは、
コンポーネントのライフサイクル(マウント・アンマウント)に合わせて自動的に呼び出されます。
特に初心者の方にとって重要なのは、依存関係の設定です。
例えば、APIからデータを取得して表示するシンプルな例を考えてみましょう。
import { useEffect, useState } from 'react';
function FetchDataComponent() {
const [data, setData] = useState(null);
useEffect(() => {
fetch("https://api.example.com/data")
.then(response => response.json())
.then(result => setData(result))
.catch(error => console.error(error));
}, []);
return (
<div>
{data ? <p>{data}</p> : <p>Loading...</p>}
</div>
);
}
JSXここでのuseEffect
の役割は、
コンポーネントが最初に表示される際(マウント時)に一度だけデータの取得処理を実行することです。
このようにAPIのデータを取得する場合は、空の依存配列[]
を渡すことで、
「一度だけ実行する」という指定ができます。
2. 依存配列を利用した制御
useEffectは第2引数に「依存配列」と呼ばれる配列を取ります。
これにより、特定の変数が変更されたときだけuseEffectが再度実行されるように指定できます。
import { useEffect, useState } from 'react';
function CounterComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(`Count has changed to: ${count}`);
}, [count]);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
JSX上記の例では、count
が変更されたときにのみuseEffect内の処理が実行されます。
このように、特定の変数が変化したタイミングで処理を実行したい場合に非常に便利です。
3. クリーンアップ処理の利用
useEffectのもう1つの特徴は、クリーンアップ処理が行える点です。
クリーンアップとは、主にタイマーやイベントリスナーの解除を行うもので、メモリリークの防止に役立ちます。
例えば、タイマーをセットして何かをカウントする場合を考えてみましょう。
import { useEffect, useState } from 'react';
function TimerComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
setCount(prevCount => prevCount + 1);
}, 1000);
return () => {
clearInterval(timer);
console.log("Timer cleared!");
};
}, []);
return (
<div>
<p>{count}</p>
</div>
);
}
JSXこの例では、コンポーネントが削除される際(アンマウント時)にタイマーを解除しています。
クリーンアップ処理を記述しないと、タイマーが残ったままになり、
メモリリークや意図しない動作の原因になる可能性があります。
useEffectの使いどころ
useEffectの使いどころについて、よくあるパターンをいくつかご紹介します。
1. APIのデータ取得(データフェッチ)
データフェッチの際にuseEffectは特に役立ちます。
依存配列を空にしておけば、初回レンダリング後に一度だけデータを取得することができ、
不要なリクエストを防ぐことができます。
2. ページタイトルやブラウザ情報の更新
ブラウザのタイトルや位置情報などの変更はuseEffect内で行います。
import { useEffect } from 'react';
function DocumentTitleComponent() {
useEffect(() => {
document.title = "新しいタイトル";
return () => {
document.title = "元のタイトル";
};
}, []);
return (
<div>
<p>ページタイトルが変更されました。</p>
</div>
);
}
JSX3. タイマーやイベントリスナーの設定と解除
先述のように、タイマーの設定と解除や、
ウィンドウのサイズ変更に対応するイベントリスナーの設定と解除もuseEffectが適しています。
ウィンドウサイズの変化を監視する例は以下のようになります。
import { useEffect, useState } from 'react';
function WindowSizeComponent() {
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWindowWidth(window.innerWidth);
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return <p>Window width: {windowWidth}px</p>;
}
JSXこの例では、ウィンドウのリサイズ時にwindowWidth
の値を更新し、
必要なくなったらイベントリスナーを解除しています。
useEffectの注意点
useEffectの利用にあたって、いくつか注意が必要な点もあります。
- 過剰な再レンダリングを防ぐために依存配列は必要最小限の値に抑えましょう。
- 非同期処理を扱う場合には、
async
関数をuseEffect内で直接使うのではなく、別に関数を定義して呼び出す形にしましょう。 - コンポーネントの寿命が終了する際にクリーンアップ処理を実装することで、無駄なメモリ使用を避けましょう。
まとめ
なんとなくuseEffectの世界観が見えて来たでしょうか?
ReactのuseEffectは、コンポーネントのレンダリング後に副作用を処理するための強力なツールです。
データ取得、イベントリスナーの設定、クリーンアップ処理など、多くの場面で役立ちます。
使い方に慣れていくことで、Reactのアプリケーション開発がもっと便利に進むはずです。
あざした