Writer: tokuyasu 更新日:2024/11/07
こんにちは、デジナーレ福岡オフィスの徳安です。
カスタムフックとは、React の組み込みフック(useState や useEffect など)を活用して、
特定の機能やロジックを再利用可能な形でまとめた関数のことです。
(例 データの取得やユーザのオンライン状態の監視、チャットルームへの接続など)
カスタムフックを使用することで、ロジックの再利用性が向上し、開発効率が改善されるだけでなく、保守性も高まります。
そこで、カスタムフックを活用する際の利点や注意点、そしてロジックを切り分けるタイミングについて整理してみました。
カスタムフックとは?
カスタムフックとは、React の組み込みフック(useState や useEffect など)を使って、
特定の機能やロジックを再利用可能な関数としてまとめたもの。
カスタムフックを使うことで、コンポーネントからロジックを分離し、
再利用できる形で関数を作成することができる。
これにより、Reactのコンポーネント内で
「UIロジック」と、「ビジネスロジック」や「状態管理」などを分離することができる。
カスタムフックを使用する利点
1. ロジックの再利用性
カスタムフックを作成すると簡単に再利用が可能になるため、
誰でも同じロジックを利用することができ、コードの記述時間を短縮することができる。
2. コンポーネントの可読性
カスタムフックを使用しロジック部分を切り出すことで、
コンポーネント内のコードがシンプルになり可読性も上がる。
カスタムフックを使用するタイミング
公式ドキュメントにもある通り、
必ずしも重複したコードをカスタムフックに切り分ける必要はない。
★カスタムフックの使用タイミングは、主に次の2つの状況
1. 重複があまりない場合でも、ロジックを明確に切り分ける必要がある場合
カスタムフックは、単にコードの重複を解消するためだけでなく、
コンポーネント内のロジックを明確に分離し、可読性や保守性を向上させるためにも有用。
■ 状態管理が複雑な場合
コンポーネント内で行うロジックが複雑になり、状態や副作用が絡む場合、
カスタムフックに切り分けることで、コンポーネントがシンプルになり、ロジックが分かりやすくなる。
■ 外部システムとの同期が必要な場合
Reactの状態管理やライフサイクルから離れて、外部システムとやり取りする必要がある場合に、
カスタムフックにそのロジックをまとめると、コンポーネントの責務を分けることができる。
2. 重複するロジックを再利用する必要がある場合
カスタムフックに切り分けることで、複数のコンポーネントで同じようなロジックを繰り返し書かなくて済むというメリットもある。
特に、同じパターンのロジックを複数回使用する場合は、カスタムフックに切り分けておくと、コードがクリーンで保守しやすくなる。
カスタムフックの構築
下記コンポーネント内に記載されているfetchData関数で行っている処理は、
多くのコンポーネントで共通するロジックであるため、
カスタムフックに切り分けることで、コードの重複を避け、保守性を高めることができる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
const Component = () => { const [data, setData] = useState(); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(); const fetchData = async () => { setIsLoading(true) try { const response = await fetch('https://example.com'); const json = await response.json(); setData(json); } catch (error) { setError(error); } finally { setLoading(false); } }; useEffect(() => { fetchData(); }, []); if (error) { return <div>Error: {error.message}</div>; } return ( <> {loading && ( <div>Loading...</div> )} {data && ( <div>data :{data}</div> // 取得したデータを展開する )} </> ); } export default Component |
関数内の処理
★コンポーネント内に記載されているfetchData関数内で行っている処理は、次の4つのステップ
-
- ローディング状態の管理(setIsLoading(true))
- APIリクエスト(try ブロック内で行う)
- エラーハンドリング(catch ブロック内で行う)
- 処理完了後にローディング状態を false に設定
この処理をカスタムフックにまとめることで、再利用可能でシンプルなコードになる。
カスタムフックの作成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
import { useState, useEffect } from "react"; const useFetch = (url) => { const [data, setData] = useState(); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(); useEffect(() => { const fetchData = async () => { setIsLoading(true); // ローディング状態の管理 try { const response = await fetch(url); //APIリクエスト if (!response.ok) { throw new Error("Failed to fetch data"); } const json = await response.json(); setData(json); } catch (error) { setError(error); // エラーハンドリング } finally { setLoading(false); // 処理完了後にローディング状態を false に設定 } }; fetchData(); }, [url]); // URLが変わるたびに再実行される return { data, loading, error }; }; export default useFetch; |
上記のカスタムフックでは、URLを引数として受け取り、
-
- ・取得したデータ(data)
- ・読み込み状況(isLoading)
- ・エラーの状態(error)
を含むオブジェクトを返却する。
カスタムフックを使用する
先ほど作成したカスタムフックをComponentコンポーネント内で使用する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import useFetch from './useFetch'; // 定義したカスタムフックをインポートする const Component = () => { const { data, loading, error } = useFetch('https://example.com'); if (error) { return <div>Error: {error.message}</div>; } return ( <> {loading && ( <div>Loading...</div> )} {data && ( <div>data :{data}</div> // 取得したデータを展開する )} </> ); } export default Component |
このように、FetchData関数をカスタムフックに切り分けることで、
コンポーネント内のロジックが整理され、より明確で再利用可能な形になる。
そして、カスタムフックにラップすることで、実装時の意図とデータの流れを正確に表現することができる。
コンポーネントの責務をデータの取得や副作用の管理から切り離し、
ビューのレンダリングに専念させることができるため、コードがシンプルで理解しやすくなる。
注意点
カスタムフックを使用する際には、以下の注意点を守ることが重要。
ルールに従うことで、コードの可読性、保守性、そして再利用性が高まる。
1.命名は必ず use で始まる
カスタムフックを使用する際には、必ず「use」で始まる名前にし、
続く単語はキャメルケース(先頭大文字)で書く。【例】useCounterなど
2.単一責任の原則
カスタムフックを作成する際には、単一の責任を持たせるようにする。
これにより、コードの可読性、再利用性、保守性が向上する。
3.同じカスタムフックを使っても state は別々に管理される
カスタムフックは、state 自体ではなく、state を扱う「ロジック」のみ共有できるようにするためのもの。
そのため、同じカスタムフックを異なるコンポーネントで使用しても、各コンポーネントの state は独立している。
4.カスタムフックは、純粋関数である必要がある
カスタムフック内のコードは、コンポーネントのレンダリングのたびに実行されるため、
コンポーネントのレンダリングに影響を与えるような副作用を持つべきではない。
まとめ
カスタムフックを使用することで、Reactアプリケーション内のロジックを整理し、
コードの再利用性、可読性、保守性を向上させることができます。
カスタムフックは、コードの重複を避けるだけでなく、
複雑な状態管理や副作用を分離するためにも有効です。
適切に使うことで、Reactアプリケーションをより効率的に開発し、保守しやすくすることができます。
ここまで読み進めていただきありがとうございます。