金子
2024.01.04
1826
明けましておめでとうございます。
inputを分割して送信時にデータを結合する方法がドキュメントや記事には書かれていなかったので
紹介したいと思います。
そもそもReactHookFormって何?と思う方もいるかもしれませんので簡単に説明すると
フォームに対してバリデーションをかけてくれるReact専用ライブラリです。
公式でも拡張機能に優れていると自負していますが、
バリデーションで言うとresolverオプションにZod、Yup などの別のバリデーションライブラリを設定することができ、
muiなどのコンポーネントライブラリと組み合わせることもできます。
muiと組み合わせるとこんな感じです。(muiはデフォルトでアニメーションがついてるのでかっこいいです!
赤文字がReact Hook Formのバリデーション部分となります。
公式のデモからも実際にフォームを入力して確かめることができます。
フォーム分割の利点はユーザの入力工数を減らせることにあります。
分割なし
1232343454565676
入力が分割されている場合
1232 3434 5456 5676
分割なし
YY/MM
入力が分割されている場合
YY MM
では本題に移っていきます。
まず完成をお見せします。
"use client";
import React, { useState } from "react";
import { useForm, SubmitHandler, Controller } from "react-hook-form";
type FormData = {
birthday: string;
};
export default function page() {
const [isValue, setIsValue] = useState("");
const {
control,
handleSubmit,
formState: { errors },
} = useForm<FormData>();
const onSubmit: SubmitHandler<FormData> = (data) => {
setIsValue(data.birthday);
};
return (
<div className="flex justify-center items-center w-screen h-screen flex-col">
{isValue && (
<p className="mb-8 text-lg">
あなたの生年月日は<span className="text-blue-600">{isValue}</span>
です。
</p>
)}
<form onSubmit={handleSubmit(onSubmit)} className="flex w-50 h-50 p-12 bg-gray-400 gap-8 flex-col">
<div>
<label>生年月日</label>
<Controller
name="birthday"
control={control}
rules={{ required: true }}
render={({ field }) => (
<div className="flex !w-2/4 items-center">
<input
className="h-6"
type="text"
name="Year"
placeholder="年"
onChange={(e) => {
const yearValue = e.target.value;
const monthValue = field.value?.split("/")[1];
const dayValue = field.value?.split("/")[2];
const newBirthdayValue = `${yearValue}/${monthValue}/${dayValue}`;
field.onChange(newBirthdayValue);
}}
maxLength={4}
/>
<p className="mx-2">/</p>
<input
className="h-6"
type="text"
name="Mouth"
placeholder="月"
onChange={(e) => {
const yearValue = field.value?.split("/")[0];
const monthValue = e.target.value;
const dayValue = field.value?.split("/")[2];
const newBirthdayValue = `${yearValue}/${monthValue}/${dayValue}`;
field.onChange(newBirthdayValue);
}}
maxLength={2}
/>
<p className="mx-2">/</p>
<input
className="h-6"
type="text"
name="Day"
placeholder="日"
onChange={(e) => {
const yearValue = field.value?.split("/")[0];
const monthValue = field.value?.split("/")[1];
const dayValue = e.target.value;
const newBirthdayValue = `${yearValue}/${monthValue}/${dayValue}`;
field.onChange(newBirthdayValue);
}}
maxLength={2}
/>
</div>
)}
/>
{errors.birthday && <p className="text-red-600">{errors.birthday.message}</p>}
</div>
<button className="h-10" type="submit">
送信
</button>
</form>
</div>
);
}
大事な部分はonChangeです。
onChange={(e) => {
const yearValue = e.target.value;
const monthValue = field.value?.split("/")[1];
const dayValue = field.value?.split("/")[2];
const newBirthdayValue = `${yearValue}/${monthValue}/${dayValue}`;
field.onChange(newBirthdayValue);
}}
この部分で結合してfieldに返してます。
const newBirthdayValue = `${yearValue}/${monthValue}/${dayValue}`;
field.onChange(newBirthdayValue);
送信してみると
/区切りになってますね。
ReactHookFormのcontrollerを複数用意して個別にバリデーションをかけたり、
結合された値にバリデーションをかけたりできるので用途に応じて柔軟に利用できるところがいいですね。
それでは、次回の記事でお会いしましょう!
717
タム
2024.04.15
267
hayasaka
2024.02.20
198
hayasaka
2024.02.02