15個の役立つカスタムReactフック
カスタムReactフックを使えば、関数コンポーネントで再利用可能なロジックを実装し、コンポーネントを分離し、その目的に集中させる小さな部分を維持できます。カスタムフックは、コンポーネント自体とは別に隔離されてテストすることで、コンポーネントのロジックを理解したりテストしたりしやすくなります。また、カスタムフックを使うと、異なるコンポーネント間でロジックを共有することが容易になり、コードの重複を減らして、コードベースの保守とアップデートがしやすくなります。
Reactフックには無限の可能性がありますが、作られたものがすべて同じとは限りません。この記事では、どんなプロジェクトでも使えて、導入が超簡単な強力なカスタムフックを15個紹介します。
注意: これらのフックは、YoutuberのWeb Dev Simplifiedが作成したものです。詳しいビデオ解説が欲しい場合は、彼のビデオをチェックしてください。ただし、読むだけでいい場合は、このまま続けてください。
目次
- useToggle
- useTimeout
- useDebounce
- useUpdateEffect
- useArray
- usePrevious
- useStateWithHistory
- useStorage
- useAsync
- useFetch
- useScript
- useDeepCompareEffect
- useEventListener
- useOnScreen
- useWindowSize
- useToggle
import { useState } from "react";
export default function useToggle(defaultValue) {
const [value, setValue] = useState(defaultValue);
function toggleValue(value) {
setValue(currentValue =>
typeof value === "boolean" ? value : !currentValue
);
}
return [value, toggleValue];
}
useToggle
は、値をtrueとfalseの間で切り替えることを可能にするカスタムReactフックです。useState
フックを使用して状態を管理します。まず、フックはdefaultValue
引数を受け取り、値の状態を初期化します。次に、現在の値と、値をtrueとfalseの間で切り替える関数であるtoggleValue
を含む配列を返します。この関数は1つのパラメータを受け取ります。パラメータがブール型の場合はその値を設定し、そうでない場合は現在値をトグルします。
このフックの使い方の例です:
import useToggle from "./useToggle";
export default function ToggleComponent() {
const [value, toggleValue] = useToggle(false);
return (
<div>
<div>{value.toString()}</div>
<button onClick={toggleValue}>Toggle</button>
<button onClick={() => toggleValue(true)}>Make True</button>
<button onClick={() => toggleValue(false)}>Make False</button>
</div>
);
}
- useTimeout
import { useCallback, useEffect, useRef } from "react";
export default function useTimeout(callback, delay) {
const callbackRef = useRef(callback);
const timeoutRef = useRef();
useEffect(() => {
callbackRef.current = callback;
}, [callback]);
const set = useCallback(() => {
timeoutRef.current = setTimeout(() => callbackRef.current(), delay);
}, [delay]);
const clear = useCallback(() => {
timeoutRef.current && clearTimeout(timeoutRef.current);
}, []);
useEffect(() => {
set();
return clear;
}, [delay, set, clear]);
const reset = useCallback(() => {
clear();
set();
}, [clear, set]);
return { reset, clear };
}
useTimeout
は、コンポーネントがタイムアウトをset
(設定)し、clear
(クリア)することを可能にするカスタムReactフックです。useCallback
、useEffect
、およびuseRef
フックをReactライブラリから使用します。フックは2つの引数を取ります:特定の遅延後に呼び出されるcallbackと、callbackが呼び出されるまでに経過すべきミリ秒単位の時間を示すdelayです。
フックは2つのプロパティを含むオブジェクトを返します:resetとclearは、タイムアウトをリセットまたはクリアするために使用できる関数です。
フックはuseRef
フックを使って2つのリファレンスを作成します:callbackRef
とtimeoutRef
です。callbackRef
はcallback関数を保持するミュータブルな値として、timeoutRef
にはsetTimeout()関数によって返されたタイムアウトIDを格納します。
useEffect
フックはcallbackRef.currentが常に最新のcallbackを持っているようにするために使用されます。
set
関数はsetTimeoutを使って新しいタイムアウトを作成し、指定された遅延後にcallback関数を呼び出します。clear関数はclearTimeoutを使ってタイムアウトをクリアします。そして、もう1つのuseEffect
フックがマウント時にタイムアウトを設定し、アンマウント時にそれを削除するために使用されます。reset
関数はclear
とset
関数の組み合わせです。最後に、useCallback
フックがその依存関係が変わったときにのみ関数が再作成されることを保証します。
このフックの使い方の例です:
import { useState } from "react";
import useTimeout from "./useTimeout";
export default function TimeoutComponent() {
const [count, setCount] = useState(10);
const { clear, reset } = useTimeout(() => setCount(0), 1000);
return (
<div>
<div>{count}</div>
<button onClick={() => setCount(c => c + 1)}>Increment</button>
<button onClick={clear}>Clear Timeout</button>
<button onClick={reset}>Reset Timeout</button>
</div>
);
}
このカスタムuseTimeout
フックは、あるコンポーネントが避けられない遅延を必要とするさまざまな状況で役立ちます。例えば:
- 一定時間後に消える通知メッセージ
- 一定時間ローディングスピナーが表示され、その後リダイレクトするフォームの送信
- 一定時間後に自動的に次のスライドに進むスライドショー
- カウントダウンタイマーが残り時間を表示し、ゼロに達するとアクションをトリガーする
- 一定時間後にフォームデータを自動保存するオートセーブ機能
- 一定時間の非活動後にユーザーをログアウトするセッションタイムアウト
- 一定時間後にコールバック実行を遅らせるデバウンス機能
特定の時間を待ってから行動を起こす必要がある場合や、遅延を挟んで同じアクションを複数回繰り返したい場合に使用することができます。
- useDebounce
import { useEffect } from "react";
import useTimeout from "../2-useTimeout/useTimeout";
export default function useDebounce(callback, delay, dependencies) {
const { reset, clear } = useTimeout(callback, delay);
useEffect(reset, [...dependencies, reset]);
useEffect(clear, []);
}
useDebounce
は、特定の時間が経過するまでコールバック関数の実行を遅らせることを可能にするカスタムReactフックです。Reactライブラリから組み込みのuseEffect
フックを使用し、useTimeout
(2番目のカスタムフック)カスタムフックを使用します。
このフックは3つの引数を取ります:
- "callback"はデバウンスされるべき関数です。
- "delay"はコールバックが呼び出されるまでに経過すべきミリ秒単位の時間です。
- "dependencies"は、変更があった場合に再度コールバックを実行するためにフックが監視する値の配列です。
フックはuseTimeout
フックを使ってタイムアウトを作成し、特定の遅延が経過した後にcallback関数を呼び出します。useEffect
フックを使って、マウント時にタイムアウトを設定し、アンマウント時にクリアします。最初のuseEffect
は依存関係が変わるたびにreset関数を呼び出し、2番目のuseEffectはコンポーネントのアンマウント時にclear関数を呼び出します。
このフックの使い方の例です:
import { useState } from "react";
import useDebounce from "./useDebounce";
export default function DebounceComponent() {
const [count, setCount] = useState(10);
useDebounce(() => alert(count), 1000, [count]);
return (
<div>
<div>{count}</div>
<button onClick={() => setCount(c => c + 1)}>Increment</button>
</div>
);
}
短時間にコールバック関数が何度も呼び出されるのを制限したい場合に役立ちます。たとえば、すべてのキーストロークでサーバーに検索リクエストを送信する入力フィールドがある場合、必要のないネットワークトラフィックを避け、ユーザーの操作体験を向上させるために、リクエストを送信する前にユーザーがタイピングを止めるのを待つべきです。
- useUpdateEffect
import { useEffect, useRef } from "react";
export default function useUpdateEffect(callback, dependencies) {
const firstRenderRef = useRef(true);
useEffect(() => {
if (firstRenderRef.current) {
firstRenderRef.current = false;
return;
}
return callback();
}, dependencies);
}
useUpdateEffect
は、特定の依存関係が変更されたときにのみコールバック関数を実行するようにするカスタムReactフックです。Reactライブラリに組み込まれているuseEffect
とuseRef
フックを使用します。
フックは2つの引数を取ります:
callback
は依存関係が変わったときに呼ばれるべき関数です。dependencies
はフックが変更を検知して反応し、コールバックを実行すべき値の配列です。
フックはuseRef
フックを使用してfirstRenderRef
という名前のリファレンスを作成します。これは初回レンダリングの時にtrueとして初期化されます。このリファレンスを使用してコンポーネントの最初のレンダリングを追跡します。
useEffectフックは依存関係の配列の変更を監視し、callback関数を呼び出します。useEffect
関数内部では、firstRenderRef
の値をチェックして、最初のレンダリングかどうかを確認します。もしそうなら、false
に設定し、それ以外の場合は変更があったのでコールバック関数を呼び出します。
このフックの使い方の例です:
import { useState } from "react";
import useUpdateEffect from "./useUpdateEffect";
export default function UpdateEffectComponent() {
const [count, setCount] = useState(10);
useUpdateEffect(() => alert(count), [count]);
return (
<div>
<div>{count}</div>
<button onClick={() => setCount(c => c + 1)}>Increment</button>
</div>
);
}
依存関係のある特定の値が変更されたときだけロジックを実行したい場合、例えばユーザーがドロップダウンメニューから特定のオプションを選択した後にAPIからデータを取得する場合や、ウィンドウのサイズが変わった後に画面上の要素の位置を更新する場合などに役立ちます。
- useArray
import { useState } from "react";
export default function useArray(defaultValue) {
const [array, setArray] = useState(defaultValue);
function push(element) {
setArray(a => [...a, element]);
}
function filter(callback) {
setArray(a => a.filter(callback));
}
function update(index, newElement) {
setArray(a => [
...a.slice(0, index),
newElement,
...a.slice(index + 1, a.length),
]);
}
function remove(index) {
setArray(a => [...a.slice(0, index), ...a.slice(index + 1, a.length)]);
}
function clear() {
setArray([]);
}
return { array, set: setArray, push, filter, update, remove, clear };
}
useArray
は、コンポーネントが配列状態を管理することを可能にするカスタムReactフックです。Reactライブラリから組み込みのuseState
フックを使います。フックは引数defaultValue
を取り、配列状態の初期化に使用されます。フックはいくつかのプロパティを含むオブジェクトを返します:
array
は現在の配列状態ですset
は配列状態を新しい値に設定するための関数ですpush
は配列の最後に要素を追加するための関数ですfilter
はコールバック関数を渡すことで配列をフィルタリングするための関数ですupdate
は配列の特定のインデックスの要素を更新するための関数ですremove
は配列の特定のインデックスの要素を削除するための関数ですclear
は配列をクリアするための関数です
こちらの記事はdev.toの良い記事を日本人向けに翻訳しています。
https://dev.to/arafat4693/15-useful-react-custom-hooks-that-you-can-use-in-any-project-2ll8