🤏
React Hook Formで、フラグを次のページに引き継ぐコツ
複数ステップにまたがるフォームを実装する際、ページ間でフラグを管理したいときがあると思います。
今回は、ReactHookFormを使って実装する際のフラグの受け渡し方を紹介してみます。
フラグの管理で最初に思い浮かぶのは、localStorageやsessionStorageです。
これらでも状態を保持することはできるのですが、リロードしてもデータが残ってしまったり、割と手間だったりするのですが、今回はフラグをsetValueでセットする方法をとってみたいと思います。
↓こちらが1ページ目です。(app/form/1/page.jsx)
"use client";
import { useRouter } from "next/navigation";
import { useEffect } from "react";
import { useFormContext } from "react-hook-form";
export default function Home() {
const { register, watch, setValue } = useFormContext();
const router = useRouter();
const planName = watch("planName") || "";
const isCurrentPlan = watch("isCurrentPlan") || "";
useEffect(() => {
console.log("選択されたプラン:", planName);
console.log("現在のプランかどうか", isCurrentPlan);
}, [watch()]);
const handleNextPage = (e) => {
e.preventDefault();
router.push("./2");
};
return (
<div className="p-10">
<form onSubmit={handleNextPage} className="flex flex-col gap-4 max-w-md">
<div className="flex flex-col gap-2">
<label className="text-lg font-semibold">プラン選択</label>
<div className="flex gap-4">
<label
className={`cursor-pointer py-2 px-4 rounded-md shadow text-lg w-full text-center
${
planName === "Aプラン"
? "bg-black text-white"
: "bg-gray-300 text-gray-800"
}`}
>
<input
type="radio"
value="Aプラン"
onClick={() => setValue("isCurrentPlan", "true")}
{...register("planName")}
className="sr-only"
/>
プランA
</label>
<label
className={`cursor-pointer py-2 px-4 rounded-md shadow text-lg w-full text-center
${
planName === "Bプラン"
? "bg-black text-white"
: "bg-gray-300 text-gray-800"
}`}
>
<input
type="radio"
value="Bプラン"
onClick={() => setValue("isCurrentPlan", "false")}
{...register("planName")}
className="sr-only"
/>
プランB
</label>
</div>
</div>
<button
type="submit"
className="bg-red-600 text-white py-2 px-4 rounded-md shadow"
>
次のページへ
</button>
</form>
</div>
);
}
こちらが2ページ目です。(app/form/2/page.jsx)
"use client";
import { useEffect } from "react";
import { useFormContext } from "react-hook-form";
export default function Home() {
const { watch } = useFormContext();
const selectedPlan = watch("isCurrentPlan") || "";
useEffect(() => {
// 現在のプランが選択された場合にfetchを実行
if (selectedPlan === "true") {
// fetch APIを使ってデータを取得
fetch("/api/getCurrentPlanData")
.then((response) => response.json())
.then((data) => {
console.log("現在のプランのデータ: ", data);
})
.catch((error) => {
console.error("API呼び出しエラー: ", error);
});
}
}, [selectedPlan]);
return (
<div className="p-10">
<p>
<span className="font-bold text-lg">
{selectedPlan === "true" ? "現在のプラン" : "他のプラン"}
</span>
を選択しました。
</p>
</div>
);
}
コードの概要としては、プランAが現在のプラン、プランBが他のプランです。
planNameだけだと、そのプランの名前しかデータとして扱えていませんでしたが、isCurrentPlanというフラグをsetValueでセットすることで、一つのボタンで2つの情報を持たせています。
1ページ目でプランAを選択すると、コンソールで「true」と表示されている。
すると、2ページ目でしっかり反映されている。
今回のように、ボタンを押した際にsetValueを追加することで、一つではなく、複数のフラグをセットすることもできます。
ただし、何も考えずsetValueでセットするのではなく、あくまでフォームに関連するフラグのみをセットするのがよいと思います。(責務の分離)フォーム以外で状態を管理したいときは、ContextやRecoilを使ったほうが良いと思います。
Discussion