Skip to content

カスタムフック

公開日:December 8, 2024更新日:December 8, 2024
ReactTypeScriptCoding📄

Reactのカスタムフックは、状態管理やロジックの再利用をシンプルにする強力なツールです。TypeScriptを活用することで、カスタムフックに型安全性を加え、予期しないエラーを防ぎながら、再利用性の高いコードを構築できます。この章では、型安全なカスタムフックの作成、再利用可能なロジックの設計、実用例について解説します。

型安全なカスタムフックの作成

カスタムフックは、useで始まる関数として定義されます。TypeScriptでは、引数と戻り値に型を定義することで、フックの意図を明確にし、再利用時の安全性を高めます。

基本例

以下は、カウントを管理するカスタムフックの例です。

tsx
import { useState } from 'react';

const useCounter = (initialValue: number = 0): [number, () => void, () => void] => {
  const [count, setCount] = useState<number>(initialValue);

  const increment = () => setCount((prev) => prev + 1);
  const decrement = () => setCount((prev) => prev - 1);

  return [count, increment, decrement];
};

export default useCounter;

解説

  • 引数の型: initialValueのデフォルト値を指定しつつ型を明示。
  • 戻り値の型: 配列型で各要素の型を明確に指定。
  • 安全性: 関数が期待通りのデータを扱うことを保証。

再利用可能なロジックの設計

カスタムフックは、ロジックを再利用可能にするために設計されます。TypeScriptを使用して汎用性を高める方法を見てみましょう。

フック内でのジェネリクスの使用

ジェネリクスを使用することで、フックの柔軟性を向上させることができます。

例: フォーム管理フック

tsx
import { useState } from 'react';

const useForm = <T extends Record<string, any>>(initialValues: T) => {
  const [values, setValues] = useState<T>(initialValues);

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = event.target;
    setValues({
      ...values,
      [name]: value,
    });
  };

  const resetForm = () => setValues(initialValues);

  return { values, handleChange, resetForm };
};

export default useForm;

使用例

tsx
interface FormValues {
  username: string;
  email: string;
}

const App = () => {
  const { values, handleChange, resetForm } = useForm<FormValues>({
    username: '',
    email: '',
  });

  return (
    <div>
      <input
        type="text"
        name="username"
        value={values.username}
        onChange={handleChange}
      />
      <input
        type="email"
        name="email"
        value={values.email}
        onChange={handleChange}
      />
      <button onClick={resetForm}>Reset</button>
    </div>
  );
};

export default App;

解説

  • ジェネリクス <T>: フォームのフィールドが柔軟に変更可能。
  • 型安全なフィールド操作: Tのフィールドのみを操作可能。

実用例: データ取得フック

データ取得のロジックをカスタムフックとして切り出すことで、再利用性を高めることができます。

データ取得フックの例

tsx
import { useEffect, useState } from 'react';
import axios from 'axios';

const useFetch = <T>(url: string) => {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState<boolean>(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        setLoading(true);
        const response = await axios.get<T>(url);
        setData(response.data);
      } catch (err: any) {
        setError(err.message || 'An error occurred');
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [url]);

  return { data, loading, error };
};

export default useFetch;

使用例

tsx
interface User {
  id: number;
  name: string;
}

const App = () => {
  const { data, loading, error } = useFetch<User[]>('https://jsonplaceholder.typicode.com/users');

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error}</p>;

  return (
    <ul>
      {data?.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
};

export default App;

解説

  • ジェネリクス <T>: 任意のデータ型に対応可能。
  • エラーハンドリング: ロード中とエラー時の状態を明確に管理。

カスタムフックを使用することで、型安全性を保ちながらロジックを再利用可能にできます。フォーム管理やデータ取得といったよくあるユースケースに対応する汎用的なフックを設計することで、コードの効率と可読性を向上させましょう。