【初心者向け】React カスタムフック徹底ガイド

はい、承知いたしました。React初心者向けに、カスタムフックの概念から具体的な作成方法、実践例、注意点、テスト方法、ベストプラクティスまでを網羅した、約5000語の詳細な解説記事を作成します。

以下が記事の内容です。


【初心者向け】React カスタムフック徹底ガイド

はじめに:なぜカスタムフックを学ぶ必要があるのか?

Reactを使った開発において、「フック(Hooks)」は今や欠かせない存在です。特にReact 16.8で導入されて以来、関数コンポーネントで状態や副作用を扱うことができるようになり、コンポーネントの書き方が大きく変わりました。

そして、このフックの強力な機能の一つが「カスタムフック」を作成できることです。初心者の方にとっては、標準で提供されている useStateuseEffect といったフックを使うだけでも最初は大変かもしれません。しかし、少しReact開発に慣れてきて、同じようなロジックを複数のコンポーネントで書いていることに気づき始めたら、それはカスタムフックを学ぶ絶好の機会です。

では、なぜカスタムフックが必要なのでしょうか? 主な理由は以下の通りです。

  1. ロジックの再利用: アプリケーション開発では、データのフェッチ、フォーム入力の検証、ウィンドウサイズの変化への対応など、様々なコンポーネントで同じようなロジックが必要になることが頻繁にあります。カスタムフックを使えば、これらの共通ロジックをカプセル化し、複数のコンポーネントで簡単に使い回せるようになります。
  2. コンポーネントの関心の分離: UIの表示ロジック(どう見えるか)と、データの取得や状態の管理といった非UIロジック(どう動くか)を分離できます。これにより、コンポーネントファイルが肥大化するのを防ぎ、よりシンプルで読みやすいコードになります。
  3. 可読性と保守性の向上: ロジックがカスタムフックとして切り出されることで、各コンポーネントは自身のUIに関することだけに集中できます。これにより、コンポーネントのコードが短く、何をしているのか理解しやすくなります。結果として、コードの保守性も向上します。
  4. テスト容易性の向上: ロジックがコンポーネントから分離されることで、UIに依存せずにロジック単体でテストしやすくなります。

この記事では、Reactや基本的なフック(useState, useEffectなど)を使ったことがある方を対象に、カスタムフックの概念から、具体的な作成方法、よくあるパターン、注意点、そしてテスト方法までを徹底的に解説します。約5000語にわたる詳細な説明を通して、カスタムフックを理解し、自信を持って使いこなせるようになることを目指します。

さあ、カスタムフックの世界へ踏み出しましょう!

Reactフックの基本おさらい

カスタムフックは、既存のReactフックを組み合わせて作られるものです。そのため、まずは基本的なフックの役割を簡単におさらいしておきましょう。

useState:状態管理のフック

関数コンポーネント内で状態(ステート)を持つために使います。

“`jsx
import React, { useState } from ‘react’;

function Counter() {
// count という状態変数と、それを更新する setCount 関数を宣言
const [count, setCount] = useState(0); // 初期値は 0

return (

カウント: {count}

);
}
“`

useState は、現在の状態の値と、その状態を更新するための関数(セッター関数)のペアを配列として返します。状態が更新されると、コンポーネントが再レンダーされます。

useEffect:副作用の処理フック

データの取得、DOMの直接操作、イベントリスナーの設定や解除、タイマー処理といった、「副作用」を関数コンポーネントで行うために使います。コンポーネントのレンダー後に実行される処理を定義します。

“`jsx
import React, { useState, useEffect } from ‘react’;

function WindowSizeDisplay() {
const [windowWidth, setWindowWidth] = useState(window.innerWidth);

useEffect(() => {
// 副作用の処理: ウィンドウサイズ変更イベントのリスナーを設定
const handleResize = () => {
setWindowWidth(window.innerWidth);
};

window.addEventListener('resize', handleResize);

// クリーンアップ関数: コンポーネントがアンマウントされる際や
// 依存配列が変更されてエフェクトが再実行される前に呼ばれる
return () => {
  window.removeEventListener('resize', handleResize);
};

}, []); // 依存配列が空なので、このエフェクトはマウント時とアンマウント時にのみ実行される

return (

ウィンドウ幅: {windowWidth}px

);
}
“`

useEffect は第一引数に副作用の処理を行う関数、第二引数に依存配列を取ります。依存配列が空([])の場合、エフェクトはコンポーネントのマウント時のみ実行され、クリーンアップ関数はアンマウント時に実行されます。依存配列に値を含めると、その値が変更されるたびにエフェクトが再実行され、その前に前回のクリーンアップ関数が実行されます。

useContext:コンテキストの使用フック

Context APIを使って、コンポーネントツリーを深く辿ることなくデータを共有するために使います。

“`jsx
import React, { useContext, createContext } from ‘react’;

// コンテキストを作成
const ThemeContext = createContext(‘light’); // 初期値は ‘light’

// コンテキストプロバイダーコンポーネント
function App() {
return (
{/ 子コンポーネントに値を共有 /}


);
}

// コンテキストを使用するコンポーネント
function ThemedButton() {
const theme = useContext(ThemeContext); // コンテキストの値を取得

return (

);
}
“`

useContext は作成したコンテキストオブジェクトを受け取り、そのコンテキストの現在の値を返します。

カスタムフックは、これらの useStateuseEffectuseContext といった標準フックや、他のカスタムフックを組み合わせて、特定のロジックを抽象化し、再利用可能にしたものです。

カスタムフックとは?

改めて、カスタムフックとは何でしょうか?

一言でいうと、「Reactの他のフック(標準フックや他のカスタムフック)を呼び出す、use で始まるJavaScriptの関数」です。

“`javascript
// これはカスタムフックです
function useSomethingCool() {
// ここで useState や useEffect などのフックを呼び出します
const [state, setState] = useState(//);
useEffect(() => { // }, [//]);

// 状態や関数、またはそれらを組み合わせた値を返します
return { state, setState };
}
“`

重要なポイントは以下の通りです。

  • ただのJavaScript関数: カスタムフック自体は、特別な構文や機能を持つものではなく、単なるJavaScriptの関数です。
  • use から始まる命名規則: 関数名が必ず use で始まる必要があります。これはReactがフックのルール(後述)を適用するために必要であり、開発者にとっても「これはフックである」ということが一目でわかる重要な規約です。
  • 他のフックを呼び出す: カスタムフックの内部では、useState, useEffect, useContext などの標準フックや、別のカスタムフックを呼び出します。カスタムフックがコンポーネント内で意味を持つのは、その中で呼び出している標準フックのおかげです。
  • UIを返さない: 通常のReactコンポーネントとは異なり、カスタムフックはJSXを返してUIを描画することはありません。カスタムフックが返すのは、状態の値、状態を更新する関数、副作用を実行する関数など、コンポーネントがUIを操作したり、状態を管理したりするために必要なロジックに関連する値です。

カスタムフックの目的は、コンポーネント間で状態を持つロジックを共有することです。同じUIロジック(例えば、特定のリストの表示)を複数の場所で使う場合はコンポーネントを作成しますが、同じ状態ロジック(例えば、APIからデータをフェッチしてローディング状態を管理する)を複数のコンポーネントで使いたい場合は、カスタムフックを作成します。

カスタムフックとコンポーネントの違い

カスタムフックとコンポーネントはどちらもコードを再利用するためのものですが、目的と使い方が異なります。

  • コンポーネント: UIの一部を定義し、再利用するために使います。Propsを受け取り、JSXを返して画面に表示します。
  • カスタムフック: 状態を持つロジックを定義し、再利用するために使います。引数としてデータや設定を受け取り、状態の値や状態を操作する関数などを返します。UIは返しません。

例えば、「ユーザー一覧を表示する」ならコンポーネント、「ユーザーデータをAPIから取得して、ローディング状態やエラー状態も管理する」ならカスタムフック、というように使い分けます。ユーザーデータを取得するカスタムフックを、ユーザー一覧コンポーネントやユーザー詳細コンポーネントなど、データを必要とする様々なコンポーネントで利用できます。

なぜカスタムフックを使うのか?(より深く)

カスタムフックの必要性について、もう少し掘り下げて考えてみましょう。Reactでフックが登場する前は、コンポーネント間でロジックを共有するために「レンダープロップス」や「高階コンポーネント(HOC)」といったパターンが使われていました。これらも強力なパターンでしたが、いくつかの課題がありました。

  • レンダープロップス: ネストが深くなりやすく、コードが読みにくくなる「ラッパー地獄」と呼ばれる問題が発生しがちでした。
  • 高階コンポーネント: コンポーネントのツリー構造が複雑になり、デバッグが難しくなったり、Propsの名前が衝突したりする問題が発生することがありました。

フック、そしてカスタムフックは、これらの課題を解決するために導入されました。カスタムフックを使うことで、コンポーネントの構造を変えることなく、ロジックだけを抽出して再利用できるようになります。

例えば、とあるモーダルコンポーネントがあり、開閉状態を isOpen というステートで管理しているとします。別の場所で全く同じ開閉ロジックを持つドロップダウンメニューコンポーネントが必要になった場合、モーダルコンポーネントから開閉に関するステート (isOpen) とその更新関数 (setIsOpen)、そして開閉を切り替える関数 (toggleOpen) をカスタムフックとして切り出せば、モーダルとドロップダウンの両方でそのフックを再利用できます。

Before: ロジックがコンポーネント内に分散している

“`jsx
// Modal.jsx
function Modal() {
const [isOpen, setIsOpen] = useState(false); // 開閉ロジック

const toggleOpen = () => setIsOpen(!isOpen); // 開閉ロジック

// … モーダルのUIを返すJSX
return (


{isOpen && (

モーダルタイトル

モーダルの中身

)}

);
}

// Dropdown.jsx
function Dropdown() {
const [isOpen, setIsOpen] = useState(false); // 開閉ロジック

const toggleOpen = () => setIsOpen(!isOpen); // 開閉ロジック

// … ドロップダウンのUIを返すJSX
return (


{isOpen && (

  • アイテム 1
  • アイテム 2

)}

);
}
“`

この例では、モーダルコンポーネントとドロップダウンコンポーネントの両方に、開閉状態を管理する全く同じ useStatetoggleOpen 関数が含まれています。

After: カスタムフックでロジックを再利用

まず、開閉ロジックをカスタムフックとして抽出します。

“`javascript
// useToggle.js
import { useState } from ‘react’;

function useToggle(initialValue = false) {
const [value, setValue] = useState(initialValue);

const toggle = () => {
setValue(currentValue => !currentValue);
};

// 現在の状態の値と、それを切り替える関数を返す
return [value, toggle];
}

export default useToggle;
“`

次に、このカスタムフックをモーダルとドロップダウンのコンポーネントで使用します。

“`jsx
// Modal.jsx
import React from ‘react’;
import useToggle from ‘./useToggle’; // カスタムフックをインポート

function Modal() {
const [isOpen, toggleModal] = useToggle(false); // カスタムフックを使用

// … モーダルのUIを返すJSX
return (

{/ カスタムフックから返された関数を使用 /}
{isOpen && ( // カスタムフックから返された状態を使用

モーダルタイトル

モーダルの中身

{/ カスタムフックから返された関数を使用 /}

)}

);
}

// Dropdown.jsx
import React from ‘react’;
import useToggle from ‘./useToggle’; // カスタムフックをインポート

function Dropdown() {
const [isOpen, toggleDropdown] = useToggle(false); // カスタムフックを使用

// … ドロップダウンのUIを返すJSX
return (

{/ カスタムフックから返された関数を使用 /}
{isOpen && ( // カスタムフックから返された状態を使用

  • アイテム 1
  • アイテム 2

)}

);
}
“`

このように、開閉ロジックが useToggle というカスタムフックとして一箇所にまとめられました。各コンポーネントは、そのカスタムフックを呼び出すだけで、必要な状態と関数を取得できます。これにより、コードの重複が解消され、よりクリーンで保守しやすいコードになりました。

さらに重要なのは、各コンポーネントが useToggle を呼び出すたびに、そのコンポーネント専用の独立した状態 (isOpen の値) が作成されるということです。つまり、モーダルが開いていても、ドロップダウンは閉じている、というように、それぞれの状態が互いに干渉することなく管理されます。カスタムフックは、ロジックを共有するだけであり、状態自体を共有するわけではないという点を理解しておくことが重要です。(もし状態を共有したい場合は、Context APIや状態管理ライブラリなどを検討します)

カスタムフックの作り方

それでは、実際にカスタムフックをどう作るのか、いくつかのステップと例を通して見ていきましょう。

カスタムフックを作る基本的な流れは以下の通りです。

  1. コンポーネント内に重複するロジック(状態管理や副作用など)があるかを見つける。
  2. そのロジックを新しいJavaScript関数として切り出す。
  3. 関数名を use から始める名前にする。
  4. 切り出した関数内で、元のコンポーネントで使用していた標準フック(useState, useEffectなど)を呼び出す。
  5. 切り出した関数が必要な状態の値、更新関数、その他のロジックを返すようにする。
  6. 元のコンポーネントで、切り出したカスタムフックを呼び出し、返り値を使ってロジックを実現する。

例1:シンプルなカウンタロジックの抽出(useState のみ)

前述の useToggleuseState を使ったシンプルな例でしたが、ここではもう少しステップを追って見てみましょう。

元のコンポーネント(例: カウンター):

“`jsx
// SimpleCounter.jsx
import React, { useState } from ‘react’;

function SimpleCounter() {
const [count, setCount] = useState(0);

const increment = () => setCount(count + 1);
const decrement = () => setCount(count – 1);
const reset = () => setCount(0);

return (

カウント: {count}



);
}
“`

このコンポーネントには、count という状態と、それを操作する increment, decrement, reset という関数があります。もし他のコンポーネントでも全く同じカウンター機能が必要になった場合、このロジックをカスタムフックとして切り出すことができます。

カスタムフックの作成 (useCounter.js):

“`javascript
// useCounter.js
import { useState } from ‘react’;

function useCounter(initialValue = 0) { // 関数名を use から始める
const [count, setCount] = useState(initialValue); // useState を呼び出す

// カウントを増やす関数
const increment = () => {
setCount(prevCount => prevCount + 1); // setState の関数形式を使うと安全
};

// カウントを減らす関数
const decrement = () => {
setCount(prevCount => prevCount – 1);
};

// カウントをリセットする関数
const reset = () => {
setCount(initialValue);
};

// コンポーネントが必要とする状態と関数をオブジェクトで返す
return {
count,
increment,
decrement,
reset,
};
}

export default useCounter;
“`

カスタムフックを使用するコンポーネント (SimpleCounterWithHook.jsx):

“`jsx
// SimpleCounterWithHook.jsx
import React from ‘react’;
import useCounter from ‘./useCounter’; // カスタムフックをインポート

function SimpleCounterWithHook() {
// カスタムフックを呼び出し、返り値を受け取る
const { count, increment, decrement, reset } = useCounter(10); // 初期値を渡すことも可能

return (

カウント: {count}



);
}
“`

これで、カウンターのロジックが useCounter というカスタムフックとして切り出され、SimpleCounterWithHook コンポーネント内で利用できるようになりました。他のコンポーネントでも同じ useCounter フックを呼び出すことで、簡単にカウンター機能を実装できます。

例2:ウィンドウサイズ取得のロジック抽出(useState + useEffect

次に、useEffect を含むロジックをカスタムフックとして切り出す例を見てみましょう。コンポーネントのマウント時にイベントリスナーを設定し、アンマウント時に解除するような副作用を含むロジックです。

元のコンポーネント(前述の WindowSizeDisplay.jsx):

“`jsx
// WindowSizeDisplay.jsx
import React, { useState, useEffect } from ‘react’;

function WindowSizeDisplay() {
const [windowWidth, setWindowWidth] = useState(window.innerWidth); // 状態

useEffect(() => { // 副作用
const handleResize = () => {
setWindowWidth(window.innerWidth);
};

window.addEventListener('resize', handleResize); // イベントリスナー設定

return () => { // クリーンアップ
  window.removeEventListener('resize', handleResize); // イベントリスナー解除
};

}, []); // 依存配列

return (

ウィンドウ幅: {windowWidth}px

);
}
“`

このロジックをカスタムフックとして切り出します。

カスタムフックの作成 (useWindowSize.js):

“`javascript
// useWindowSize.js
import { useState, useEffect } from ‘react’;

function useWindowSize() { // 関数名を use から始める
const [windowSize, setWindowSize] = useState({ // 状態をオブジェクトで管理
width: window.innerWidth,
height: window.innerHeight,
});

useEffect(() => { // useEffect を呼び出す
// ウィンドウサイズ変更をハンドリングする関数
const handleResize = () => {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
};

// イベントリスナーを設定
window.addEventListener('resize', handleResize);

// クリーンアップ関数を返す
return () => {
  // イベントリスナーを解除
  window.removeEventListener('resize', handleResize);
};

}, []); // 依存配列が空なので、マウント時に一度だけ実行、アンマウント時にクリーンアップ

// ウィンドウサイズの状態を返す
return windowSize;
}

export default useWindowSize;
“`

カスタムフックを使用するコンポーネント (ResponsiveComponent.jsx):

“`jsx
// ResponsiveComponent.jsx
import React from ‘react’;
import useWindowSize from ‘./useWindowSize’; // カスタムフックをインポート

function ResponsiveComponent() {
// カスタムフックを呼び出し、ウィンドウサイズの状態を取得
const windowSize = useWindowSize();

// ウィンドウ幅に基づいて表示内容を切り替える例
const isMobile = windowSize.width < 768;

return (

レスポンシブコンポーネント

現在のウィンドウ幅: {windowSize.width}px

現在のウィンドウ高さ: {windowSize.height}px

{isMobile ? (

これはモバイル表示です。

) : (

これはデスクトップ表示です。

)}

);
}
“`

これで、ウィンドウサイズを取得し、それに応じて状態を更新するというロジックが useWindowSize カスタムフックとして分離されました。このフックを使えば、様々なコンポーネントで現在のウィンドウサイズを簡単に取得し、レスポンシブな表示を実装できます。イベントリスナーの設定と解除といった副作用の管理も、フック内部に隠蔽されています。

実践的なカスタムフックの例

ここからは、実際のアプリケーション開発でよく使われるであろう、より実践的なカスタムフックの例をいくつか見ていきましょう。

例3:データの取得 (useFetch)

APIからデータを取得し、ローディング状態やエラー状態も管理するロジックは、多くのアプリケーションで共通して必要になります。これをカスタムフックとして実装してみましょう。

このフックでは、以下の状態を管理します。

  • data: 取得したデータ
  • loading: データ取得中かどうかを示すブール値
  • error: データ取得中に発生したエラー

カスタムフックの作成 (useFetch.js):

“`javascript
// useFetch.js
import { useState, useEffect } from ‘react’;

// データ取得関数 (ここでは fetch API を使用)
async function fetchData(url) {
const response = await fetch(url);
if (!response.ok) {
// HTTPエラーレスポンスの場合
throw new Error(HTTP error! status: ${response.status});
}
const data = await response.json();
return data;
}

function useFetch(url) { // 引数としてデータの取得元URLを受け取る
const [data, setData] = useState(null); // 取得したデータ
const [loading, setLoading] = useState(true); // ローディング状態
const [error, setError] = useState(null); // エラー状態

useEffect(() => {
// fetch は副作用なので useEffect 内で実行
setLoading(true); // リクエスト開始前にローディング状態をtrueにする
setError(null); // エラー状態をリセット

fetchData(url) // 定義したデータ取得関数を呼び出す
  .then(result => {
    setData(result); // 成功したらデータをセット
  })
  .catch(err => {
    setError(err); // エラーが発生したらエラー状態をセット
  })
  .finally(() => {
    setLoading(false); // リクエスト完了後にローディング状態をfalseにする (成功・失敗どちらでも)
  });

// ★ 重要: コンポーネントがアンマウントされた後にステートを更新しようとするとエラーになる可能性があるため、
// AbortController を使ってフェッチ処理をキャンセルできるようにする(より堅牢な実装の場合)
// ここではシンプルにするため省略しますが、実運用では考慮が必要です。
// もしくは、isMounted のようなフラグを管理する方法もあります。

// 例えば、AbortControllerを使う場合は以下のようなコードを追加
// const abortController = new AbortController();
// const signal = abortController.signal;
// fetchData(url, { signal }) // fetch関数のオプションにsignalを渡す
//   .then(...)
//   .catch(err => {
//     if (err.name === 'AbortError') {
//       console.log('Fetch aborted'); // アンマウントによるキャンセル
//     } else {
//       setError(err);
//     }
//   })
//   .finally(() => {
//     setLoading(false);
//   });
// return () => abortController.abort(); // クリーンアップでキャンセル

}, [url]); // 依存配列に url を含めることで、url が変更されたときに再フェッチを行う

// データ、ローディング状態、エラー状態をオブジェクトとして返す
return { data, loading, error };
}

export default useFetch;
“`

カスタムフックを使用するコンポーネント (UserDataDisplay.jsx):

“`jsx
// UserDataDisplay.jsx
import React from ‘react’;
import useFetch from ‘./useFetch’; // カスタムフックをインポート

function UserDataDisplay({ userId }) {
// カスタムフックを呼び出し、ユーザーデータのURLを渡す
// 例: JSONPlaceholder の Users API
const { data: user, loading, error } = useFetch(https://jsonplaceholder.typicode.com/users/${userId});

if (loading) {
return

ユーザーデータを読み込み中…

;
}

if (error) {
return

ユーザーデータの取得に失敗しました: {error.message}

;
}

// データが取得できたら表示
return (

ユーザー情報

{user ? ( // user が null でないことを確認
<>

名前: {user.name}

メール: {user.email}

ウェブサイト: {user.website}

) : (

ユーザーデータがありません。

)}

);
}

// このコンポーネントを App.js などで呼び出す例
//
// // 別のユーザーのデータを取得する場合も同じフックを使える
“`

これで、URLを渡すだけでデータ取得、ローディング、エラーの管理をまとめて行ってくれる useFetch カスタムフックが完成しました。このフックを使えば、データの表示を担当するコンポーネントのコードが大幅にシンプルになります。

例4:フォーム入力の管理 (useForm)

フォームの入力値やその変更、送信処理を管理するロジックも、カスタムフックとして抽象化するのに適しています。

このフックでは、以下の状態と関数を管理します。

  • values: 各入力フィールドの値を持つオブジェクト
  • handleChange: input, select, textarea 要素の onChange イベントハンドラー
  • handleSubmit: フォームの onSubmit イベントハンドラー(コールバック関数を受け取る)
  • (オプション)errors: 入力値のバリデーションエラーを持つオブジェクト
  • (オプション)isSubmitting: 送信処理中かどうかを示すブール値

ここではシンプルに、入力値の管理と変更ハンドラー、送信ハンドラーを実装します。

カスタムフックの作成 (useForm.js):

“`javascript
// useForm.js
import { useState } from ‘react’;

// initialValues は { fieldName: initialValue, … } の形式を想定
function useForm(initialValues = {}) {
const [values, setValues] = useState(initialValues);
// 後々バリデーションを追加するなら useState(initialErrors) なども追加

// 入力値が変更されたときのハンドラー
// イベントオブジェクトを受け取り、name属性とvalue属性を使って状態を更新
const handleChange = (event) => {
// イベントから name (フィールド名) と value (入力値) を取得
// チェックボックスやラジオボタンの場合は event.target.checked を使うなど、型に応じた処理が必要になることも
const { name, value } = event.target;
setValues({
…values, // 現在の値をコピー
[name]: value, // 変更されたフィールドの値を更新
});
};

// フォームが送信されたときのハンドラー
// onSubmit コールバック関数を受け取り、フォームのデフォルト動作を防ぎ、コールバックを実行する
const handleSubmit = (onSubmitCallback) => (event) => {
event.preventDefault(); // フォームのデフォルト送信動作を防ぐ (ページ遷移など)
// ここでバリデーションロジックを実行することも可能
// if (validate(values)) { … }

// 受け取ったコールバック関数に入力値を渡して実行
// コールバック内でAPI送信などの非同期処理を行うことを想定
onSubmitCallback(values);

// 送信後にフォームをリセットしたい場合は setValues(initialValues); など

};

// 入力値の状態、変更ハンドラー、送信ハンドラーをオブジェクトで返す
return {
values,
handleChange,
handleSubmit,
// 後々バリデーションエラーや送信中状態などを追加するならここに追加
// errors,
// isSubmitting,
};
}

export default useForm;
“`

カスタムフックを使用するコンポーネント (ContactForm.jsx):

“`jsx
// ContactForm.jsx
import React from ‘react’;
import useForm from ‘./useForm’; // カスタムフックをインポート

function ContactForm() {
// useForm フックを呼び出し、初期値を設定
const { values, handleChange, handleSubmit } = useForm({
name: ”,
email: ”,
message: ”,
});

// フォーム送信時の処理を定義する関数
const submitForm = (formValues) => {
console.log(‘フォームが送信されました:’, formValues);
// ここでAPIにデータを送信するなどの処理を行う
alert(‘フォームを送信しました!コンソールを確認してください。’);
};

// handleSubmit に submitForm 関数を渡す
const onSubmit = handleSubmit(submitForm);

return (

{/ useForm から返された onSubmit ハンドラーを設定 /}




上部へスクロール