#目次
#はじめに
この記事では、React 16.8で導入されたHooksの機能の一つで、関数コンポーネントにライフサイクルメソッドを記述することのできる**useEffect
**についてまとめています。現在ReactやHooksについて学習中の方の一助となれば幸いです。
###前提条件
###環境
導入 | version |
---|---|
react | 16.13.1 |
#useEffectとは
**useEffect
**は簡単にいうと、関数コンポーネントにライフサイクルメソッドを持たせるための機能です。
Hooksが導入される以前のReactでは、コンポーネントにライフサイクルメソッドを持たせるためにはクラスコンポーネントで記述する必要がありました。そのためはじめは関数コンポーネントで記述していたコンポーネントにライフサイクルイベントを追加する必要が出てきたときにわざわざクラスコンポーネントに変換しなければなりませんでした。このような問題を解決する手段としてuseEffect
が利用できます。
useEffect
では、クラスコンポーネントで利用していたライフサイクルメソッドであるcomponentDidMount
、componentDidUpdate
、componentWillUnmount
を1種類の関数で扱うことができます。
またHooksがないときにはクラスコンポーネントと関数コンポーネントが混在していましたが、useEffect
やuseState
などのHooksの機能を利用することで全てを関数コンポーネントで記述できるため、コード全体の可読性を高めることもできるでしょう。
#useEffectが呼び出されるタイミング
はじめに、関数コンポーネントがレンダリングおよび再レンダリングされるタイミングについて説明します。
初回レンダリングのタイミング:
- 関数コンポーネントがJSXとして読み込まれたとき
再レンダリングのタイミング:
- 親コンポーネントが再レンダリングされたとき
- 受け取っている
props
に変化が生じたとき - 同コンポーネント内で
useState
を用いて定義している変数に変化が生じたとき
など
useEffect
はこのようなレンダリングのタイミングで、自身で指定した任意の変数に変化が生じたときにコールバックとして記述した処理を実行します。
#useEffectの使い方
では実際にuseEffect
の使い方について見ていきましょう。useEffect
の書き方の違いで呼び出される条件が変化するので、しっかり抑えておきましょう。
###useEffectを利用するための基本
useEffectのインポート
何か別のライブラリを読み込む必要はなく、Reactからインポートして使用できます。
import React, { useEffect } from 'react'; // ここでuseEffectをインポートする
useEffectの基本構文
useEffect
には第一引数としてコールバック関数、第二引数として任意の変数を格納する配列を記述します。
なお第二引数は省略可能です。
useEffect(() => {
// 処理
}, [/* 任意の変数 */]);
以上がuseEffect
を利用するための基本となります。
次に使用目的ごとに実際の記述方法について見ていきます。
###レンダリングされるタイミングで毎回実行する
初回レンダリング時および再レンダリングに毎回useEffect
に渡したコールバック関数を実行する方法について説明します。
レンダリング時に毎回実行する方法は、useEffect
の第二引数を省略することです。
import React, { useEffect } from 'react';
const App = () => {
useEffect(() => {
// 処理
}); // 第二引数を省略
return (
// JSX
);
};
※ ただし第二引数を省略し、レンダリング時に毎回実行するようにすると何らかの原因で無限ループに陥る可能性があるので極力このような記述はしない方がいいでしょう。
###初回レンダリング時のみ実行する
クラスコンポーネントのライフサイクルメソッドのcomponentDidMount
のように初回レンダリング時にのみ処理を実行したいときは、第二引数の配列を空にして記述します。
import React, { useEffect } from 'react';
const App = () => {
useEffect(() => {
// 処理
}, []); // 第二引数の配列を空にする
return (
// JSX
);
};
###任意の変数が変化したときのみ実行する
関数コンポーネント内で使用している変数に変化が生じたときに、useEffect
に渡したコールバック関数を実行したいときには、第二引数の配列にその変数を指定します。
少し具体的な例として、ボタンを押すと数値が加算されるカウンターを作成してみます。
import React, { useState, useEffect } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
useEffect(() => {
console.log('useEffect!!')
}, [count]); // 第二引数の配列に任意の変数を指定(ここではcountが変化した時のみ実行されるようにしている)
return (
<div>
{count}
<button onClick={() => setCount((prevCount) => prevCount + 1)}>
ADD 1
</button>
</div>
);
};
簡単な例ではありますが、このように記述することでcount
が変化したときにのみuseEffect
に渡しているコールバック関数が実行されます。
以上がuseEffect
の基本的な使い方です。
#useEffectで非同期処理をする
useEffect
内の() => {}
には非同期関数または**promise
**を返す関数を記述することができません。
ではどのようにuseEffect
で非同期処理を行えばいいのでしょうか。
結論としては2通りの方法があります。
- 方法1
useEffect
の外で別の関数を定義し、その関数をuseEffect
で呼び出す
- 方法2
async, await
を利用して特殊な記述をする
方法1については何となくイメージができると思いますので、ここでは方法2について詳しい記述方法を紹介します。
import React, { useEffect } from 'react';
const App = () => {
useEffect(() => {
(async () => {
await // 処理
})();
}, [/* 任意の変数 */]);
return (
// JSX
);
};
少し見慣れない書き方かもしれませんがこのように記述することで、useEffect
で非同期処理を行うことができます。
誤って、
// BAD example!!
useEffect(async () => {
await // 処理
}, [/* */])
としないように注意しましょう。
#まとめ
簡単ではありますが、useEffect
についての説明は以上になります。
まとめると、
-
useEffect
は関数コンポーネントでライフサイクルメソッドを持たせるための機能 - クラスコンポーネントで利用していたライフサイクルメソッドを一つの関数で表現できる
- 記述の仕方で実行タイミングが変わる
- 非同期処理させるためには注意が必要
といった感じです。
実際にはuseEffect
の使い方としてはまだまだたくさんありますが、基本中の基本はこの記事にまとめてあることなのでしっかり抑えていただければと思います。
今後アプリケーションを作成する際に、適した使い方をしていきましょう。
また参考資料に記載しているリンク先ではさらに詳しい使い方や解説をしてくれていますので、是非みて見てください。
#参考資料