当サイトは、アフィリエイト広告を利用しています
Reactで開発する時によく使うカスタムフックについてまとめる。
当記事では
について実装しながら解説する
カスタムフックとは、Reactの組み込みフック (useState, useEffect, など)を
使って自分で作る再利用可能な関数のこと。
つまり下記のようなイメージ
Reactのフック(組み込みフックとカスタムフック)には大きく分けると
の2つのルールがある。
フックのルール(Rules of Hooks)は
でReactのすべてのフックに適用されるので
カスタムフックもReactの組み込みフック同様、このルールに従って作成、使用する必要がある。
いわば一番上のルール!
詳しくは下記記事参照
カスタムフックを作成する場合、フックのルール(Rules of Hooks)のルールを
守った上でさらに固有のルールがある。
そしてそのルールはマスト(必須)とベストプラクティス(推奨)に分類できる
マストなルールとしては
がある。
これはReactの仕様やESLintのルールに関わるため絶対順守する
ベストプラクティスは守らなくても動作はするが
コードの品質や保守性を高めるためには順守することが推奨されるルール
基本的に実装が難しいものではないので順守するようにしておく。
上記の1~5までのルールを順守したカスタムフックをサンプルとして作成してみる
import { useState } from 'react';export const useCounter = () => {const [count, setCount] = useState(0);const increment = () => setCount((c) => c + 1);const decrement = () => setCount((c) => c - 1);return { count, increment, decrement };};
import React from 'react';import { useCounter } from './useCounter';export default function App() {const { count, increment, decrement } = useCounter();return (<div><p>{count}</p><button onClick={increment}>+1</button><button onClick={decrement}>-1</button></div>);}
実際の動作サンプル
カスタムフックを作成し、使用するメリットについてもまとめておく。
メリットとしては下記が考えれれる。
複数のReactの組み込みフックを使っている場合、それがどのロジックと
関係があるのがわかりにくいことがあるが、カスタムフックにすることで
フックとロジックを一箇所に集約できる
たとえば
をカスタムフックに切り出すことで、コンポーネントはUIのみに集中できる。
この点からもUIロジックはカスタムフックに入れるべきではない。
こうすることでJSXがすっきりして読みやすくなる。
複数のコンポーネントで同様の処理をする場合に
汎用的な処理をカスタムフックにすることで共通的に使用できる。
カスタムフックの利点を説明するサンプルを実装する
import { useState, useEffect } from 'react';export const useCounter = (initial = 0) => {const [count, setCount] = useState(initial);const increment = () => setCount((c) => c + 1);const decrement = () => setCount((c) => c - 1);useEffect(() => {console.log(`Count changed: ${count}`);}, [count]); // count が変わるたびにログを出すreturn { count, increment, decrement };};
import React from 'react';import { useCounter } from './useCounter';export default function App() {const { count, increment, decrement } = useCounter();return (<div><p>{count}</p><button onClick={increment}>+1</button><button onClick={decrement}>-1</button></div>);}
Reactの組み合わせフック(useState, useEffect など)を使う処理は、
カスタムフックとして定義するのが適している
一方で、Reactのフックを使わない純粋な処理(例:日付フォーマット、文字列変換など)は、
通常の関数として定義すれば十分。
よくあるパターンとして
の処理を行うカスタムフックが多い気がする ※状態管理系はサンプルで説明してるので割愛
非同期通信を行うカスタムフックをサンプルとして実装してみる
import { useState, useEffect } from 'react';export const useFetchData = (url) => {const [data, setData] = useState(null);const [isLoading, setIsLoading] = useState(true);const [error, setError] = useState(null);useEffect(() => {if (!url) {return;}const fetchData = async () => {setIsLoading(true);try {const response = await fetch(url);if (!response.ok) {throw new Error('Fetch failed: response not OK');}const json = await response.json();setData(json);} catch (err) {setError(err);} finally {setIsLoading(false);}};fetchData();}, [url]);return { data, isLoading, error };};
import React from 'react';import { useFetchData } from './useFetchData';export default function App() {const { data, isLoading, error } = useFetchData('https://jsonplaceholder.typicode.com/users');if (isLoading) {return <p>Loading...</p>;}if (error) {return <p>Error: {error.message}</p>;}return (<ul>{data.map((user) => {return <li key={user.id}>{user.name}</li>;})}</ul>);}
Reactのカスタムフックの作成方法と使い方についてまとめてみた。
カスタムフックはうまく使うと開発効率や保守性が格段に上がるので
もっと勉強していきたい。