🏠
【React】軽量なFormライブラリ「HouseForm」を試してみた
概要
ReactでのFormのライブラリとなると、2023年現在ではReact Hook Form
やFormik
が使われることが多いかと思います。私はReact Hook Formを使用することが比較的あるのですが、機能が複雑な部分は感じておりドキュメントを読み込まないと、使いこなすのは少し大変な印象はあります。
もちろん大きめの開発ならReact Hook Formを採用することは全然妥当と思いますが、少し小さめの開発でライトに使えそうなFormのライブラリはあるかと探してみました。今回はHouseFormというライブラリを少し試してみたので紹介します。
HouseFormについて
2023年にv1がリリースされたライブラリです。Comparison Against Other Form Librariesに他ライブラリとの比較がまとめられています。かなりざっくりまとめると、
- 軽量なライブラリである。
- バリデーションにzodを使える。
- インプット項目に対して柔軟に制御ができる。
といった点が特徴かなと感じました。
実装サンプル
取り急ぎ、以下のような画面を実装した時のサンプルです。
使用したHouseFormのバージョンは1.11.0
です。なお、UIのライブラリについては今回flowbite-react
やTailwind Variants
といったのを使用していますが、他のものでも問題なく使用できると思います。
import React, { FC } from "react";
import { Button, Label, TextInput } from "flowbite-react";
import { Field, Form } from "houseform";
import { z } from "zod";
import {
formBlockStyle,
inputLabelStyle,
inputTextStyle,
} from "@/style/FormStyle";
import { errorMessageStyle } from "@/style/MessageStyle";
import { centerHorizonContainerStyle } from "@/style/CommonStyle";
type UserRegisterForm = {
userId: string;
name: string;
};
export const UserRegisterComponent: FC = () => {
return (
<Form<UserRegisterForm>
onSubmit={(values) => {
console.log(values);
}}
>
{({ submit }) => (
<div>
<Field<string>
name="userId"
onSubmitValidate={z.string().nonempty("ユーザIDの入力は必須です")}
>
{({ value, setValue, errors }) => (
<div className={formBlockStyle()}>
<Label
htmlFor="userId"
value="ユーザID"
className={inputLabelStyle({ type: "required" })}
/>
<TextInput
id="userId"
value={value}
onChange={(e) => setValue(e.target.value)}
className={inputTextStyle()}
/>
{errors.map((error) => (
<p key={error} className={errorMessageStyle()}>
{error}
</p>
))}
</div>
)}
</Field>
<Field<string>
name="name"
onSubmitValidate={z.string().nonempty("名前の入力は必須です")}
>
{({ value, setValue, errors }) => (
<div className={formBlockStyle()}>
<Label
htmlFor="name"
value="名前"
className={inputLabelStyle({ type: "required" })}
/>
<TextInput
id="name"
value={value}
onChange={(e) => setValue(e.target.value)}
className={inputTextStyle()}
/>
{errors.map((error) => (
<p key={error} className={errorMessageStyle()}>
{error}
</p>
))}
</div>
)}
</Field>
<div className={`${centerHorizonContainerStyle()} mt-4`}>
<Button
color="success"
pill
onClick={() => {
submit();
}}
>
<p>登録</p>
</Button>
</div>
</div>
)}
</Form>
);
};
所感など
- インプット要素で使用するHouseFormの機能は主に
value, setValue, errors
になる感じなので、HouseFormに引っ張られずUIをけっこう柔軟に作れる感じがしました。 - バリデーションのタイミングを、フィールド毎に制御できるのが良い感じがします。
onSubmitValidate
やonBlurValidate
なども設定できます。 - ジェネリクスを使用した型指定がけっこう良さげで、型指定すればよしなに判断してくれる感じです。
- 今回試してませんが、Nested Field ValuesやForm Arraysも、そこまで苦労なく実装できそうなイメージです。
Discussion