【React】基本的なuseEffectの使い方と実用例
まず前提として、この記事を書いているのは未経験からプログラミングに挑戦中の者になります。学習はフィヨルドブートキャンプに参加しながら取り組んでいて、現役のエンジニアの方からレビューをもらいながら進めています。 現在の学習状況は以下を随時更新しているので興味ある方はご覧ください。 そのため、学んだことを不定期に初学者向けにアウトプットしています。 Reactの 副作用とは、データの取得、DOMの変更など、コンポーネントのレンダリング結果に影響を与える操作のことを指します。 たとえば、DOMの更新後に特定の操作を実行したり、外部APIからデータをフェッチしたり、イベントリスナーを設定したりする場合などに利用されます。 この例では、 配列内に特定の状態やプロップスを指定すると、その値が変更された時のみ副作用が実行されます。 依存配列を省略すると、コンポーネントがレンダリングされるたび(状態やpropsが更新されるたび)に副作用が実行されます。 ただし、多くの場合、パフォーマンスの観点から無駄な再実行を避けるために、依存配列を適切に設定することが推奨されるようです。 先ほど記述したように第2引数に空の配列を設定した場合は、初回のレンダリング後に1回だけ実行されます。 この場合、副作用はコンポーネントがマウントされた時に一度だけ実行され、アンマウント時や値の更新時には実行されません。 APIからデータを取得する、イベントリスナーを設定する、タイマーを設定するなど、コンポーネントのライフサイクル中に一度だけ行いたい操作に適しているようです。 この場合、 基本的効果は分かりましたが、どんな場面でどう使うのかがイメージがつかなかったので少し調べてみました。 APIからデータをフェッチしてコンポーネントに表示する場合、 ウィンドウサイズの変更やキーボードイベントなど、特定のイベントに対するリスナーを設定する場合に また、コンポーネントのアンマウント時にこれらのイベントリスナーをクリーンアップ(削除)することも重要。 DOM要素に対して外部ライブラリ(例えば、チャートライブラリやスライダーライブラリ)を適用する場合、 レンダリング後にDOMが準備完了していることを保証するために
副作用が特定の条件(初回マウント時、特定の依存値の変更時など)でのみ実行されるように、依存配列を適切に使用することにより、不要な副作用の実行を防ぎ、パフォーマンスを最適化することができる。 使うにあたって注意すべき点についても調べてみました これは、useEffect のコールバック関数が戻り値としてクリーンアップ関数を期待しているのが理由のようです。非同期関数は Promise を返すため、そのため期待した動きにならなくなります。 非同期処理を 間違った使用例: 上記のコードは、useEffect のコールバック関数として非同期関数を直接渡している。結果、この非同期関数は Promise を返すため、useEffect の期待するクリーンアップ関数を返していない例となる。 正しい使い方は、useEffect のコールバック関数の内部に非同期関数を定義し、呼び出すようにしてあげる。 正しい使用例: このコードでは、useEffect フックの内部で非同期関数 fetchData を定義し、即座にそれを呼び出している。 依存配列 [] が空なので、この useEffect フックはコンポーネントの初回マウント時に1回だけ実行される。 fetchData 関数内では、非同期にデータをフェッチし、成功した場合は結果をコンソールに出力し、エラーが発生した場合はエラーメッセージをコンソールに出力されます。 誤った例: 使っていく中でまた、気づいたことがあれば追記していきたいと思います! Reactのチュートリアルで学習を進めていく中で、いまいちどんな場面で 私も学習中のみなので、レベルが上げて、また新しい発見があれば発信していきたいと思います。はじめに
前提
useEffectとは
useEffect
は、関数コンポーネント内で副作用(side effects)を扱うためのフック(Hooks)です。基本的な使い方
// まずインポートする
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// コンポーネントがレンダリングされるたびに実行されます
useEffect(() => {
document.title = `クリック回数: ${count} 回`;
});
return (
<div>
<p>クリック回数: {count} 回</p>
<button onClick={() => setCount(count + 1)}>
クリック
</button>
</div>
);
}
useEffect
内でドキュメントのタイトルを更新しています。useEffect
に渡された関数は、コンポーネントの初回レンダリング後と、その後の各レンダリング後に実行されます。依存配列(Dependency Array)
useEffect
の第二引数に空の配列([]
)を渡すと、副作用はコンポーネントの初回レンダリング時にのみ実行され、その後は実行されません。useEffect(() => {
console.log('この副作用は初回レンダリング時にのみ実行されます');
}, []); // 空の依存配列
useEffect(() => {
console.log(`countが更新されました: ${count}`);
}, [count]); // countのみを依存配列に指定
依存配列の例
0. 第二引数に何も指定しなかった場合
useEffect(() => {
// この副作用はコンポーネントのレンダリング後に毎回実行されます。
});
1. 空の配列を指定した場合
useEffect(() => {
console.log('コンポーネントがマウントされた時に一度だけ実行されます');
}, []);
2. 依存配列に値を指定した場合
const [count, setCount] = useState(0);
useEffect(() => {
console.log(`countが更新されました: ${count}`);
}, [count]);
count
の値が変更されるたびに副作用が実行されます。count
以外の状態が変更されても副作用は実行されません。useEffectの実用例
実用例①データフェッチング
useEffect
を使用してデータの取得を行います。これにより、コンポーネントが画面に表示された直後にデータがロードされます。function App() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => setData(data));
}, []); // 空の依存配列を渡すことで、コンポーネントのマウント時にのみ実行されます
return (
<div>
{data ? <div>{data.name}</div> : 'Loading...'}
</div>
);
}
実用例②イベントリスナーの設定とクリーンアップ
useEffect
が役立つ。function App() {
useEffect(() => {
const handleResize = () => console.log('Window resized');
window.addEventListener('resize', handleResize);
// クリーンアップ関数
return () => window.removeEventListener('resize', handleResize);
}, []); // 空の依存配列
return <div>Hello World</div>;
}
実用例③外部ライブラリの統合
useEffect
内でライブラリの初期化コードを実行します。useEffect
を使用します。function Chart() {
useEffect(() => {
// Chart.jsの初期化など
const ctx = document.getElementById('myChart').getContext('2d');
new Chart(ctx, {
// Chart.jsの設定
});
}, []);
return <canvas id="myChart"></canvas>;
}
実用例④ タイマーの設定
setTimeout
やsetInterval
を使って、一定時間後に何かを実行する。useEffect(() => {
const timerId = setTimeout(() => {
console.log('このメッセージは3秒後に表示されます');
}, 3000);
return () => clearTimeout(timerId); // タイマーをクリア
}, []); // 空の依存配列を使用
使用するにあたって注意すべき点
①useEffect に渡すコールバック関数を Promise にしてはいけない
useEffect
に非同期関数を直接渡すことは推奨されていないとのことです。useEffect
内で扱う正しい方法は、コールバック関数内で非同期関数を定義し、それを直接呼び出すことです。useEffect(async () => {
const response = await fetch('https://api.example.com/data');
console.log(response);
}, [query]);
import React, { useEffect } from 'react';
const SimpleExample = () => {
useEffect(() => {
// 非同期関数を定義
const fetchData = async () => {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Fetching data failed', error);
}
};
// 非同期関数を呼び出し
fetchData();
}, []); // 空の依存配列を指定して、コンポーネントのマウント時に1回だけ実行されるようにする
return <div>Check the console for data.</div>;
};
②不必要な再レンダリングの引き起こし
useEffect
内でステートを更新すると、そのコンポーネントが再レンダリングされます。依存配列を正しく設定しないと、無限ループに陥ることがある。function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
setCount(count + 1); // これにより再レンダリングがトリガーされる
// 依存配列に何も指定していないため、再レンダリングの度に実行される
});
}
さいごに
useEffect
を使うの分からなかったので調べたので、ブログにもまとめてみました。