ロジックの共通化

Reactでは、UIとロジックを分離・再利用することがコードの保守性向上に繋がります。特に複数のコンポーネントで同様の挙動が必要なケースでは、カスタムフックによる共通化が非常に効果的です。


カスタムフックとは?

Reactのフックを内部で利用する再利用可能な関数です。useで始める名前にし、UIを持たないロジック部分のみを提供します。


なぜ共通化が重要か?

以下のような状況で重宝します。

  • 複数のフォームで同じバリデーション処理をしたい
  • 複数の画面で同じAPIを叩きたい
  • コンポーネント間で一貫した振る舞いを持たせたい

例:カスタムフックでウィンドウサイズ取得

// useWindowSize.ts
import { useState, useEffect } from 'react';

export const useWindowSize = () => {
  const [size, setSize] = useState({ width: window.innerWidth, height: window.innerHeight });

  useEffect(() => {
    const handleResize = () => {
      setSize({ width: window.innerWidth, height: window.innerHeight });
    };

    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return size;
};

使い方:

const App = () => {
  const { width, height } = useWindowSize();
  return 
<p>画面サイズ: {width}px × {height}px</p>;
};

例:フォーム入力を一括管理

// useForm.ts
import { useState } from 'react';

export const useForm = <T extends object>(initialValues: T) => {
  const [values, setValues] = useState
<T>(initialValues);

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

  return { values, handleChange };
};

使い方:

const Form = () => {
  const { values, handleChange } = useForm({ name: '', email: '' });

  return (

<form>
      <input name="name" value={values.name} onChange={handleChange} />
      <input name="email" value={values.email} onChange={handleChange} />
    </form>
  );
};

複数フックの組み合わせも可能

const useEnhancedForm = () => {
  const form = useForm({ name: '', email: '' });
  const size = useWindowSize();
  return { ...form, ...size };
};

よくあるユースケース

シーン フック名例
フォーム管理 useForm, useInput
API通信 useFetch, usePost, useAxios
状態トグル useToggle
イベントハンドリング useEventListener
メディアクエリ useMediaQuery

まとめ

カスタムフックを使うことで、

  • 再利用性の高いコードになる
  • UIロジックの分離が進む
  • テストや保守がしやすくなる

というメリットがあります。業務コードの中でも積極的に導入していきましょう。

コメントを残す 0

Your email address will not be published. Required fields are marked *