Form フォーム
LhForm + LhFormItem からなる複合コンポーネントで、データバリデーション、エラー表示、ラベルの整列などの機能を提供します。
基本的な使い方
import { useRef, useState } from 'react'
import { LhButton, LhForm, LhFormItem, LhInput, LhSelect } from '@lh-ui/react'
import type { LhFormInstance, LhFormRule } from '@lh-ui/react'
interface FormData {
name: string
style: string
}
const rules: Record<string, LhFormRule[]> = {
name: [{ required: true, message: '作品名を入力してください', trigger: 'blur' }],
style: [{ required: true, message: '画風を選択してください', trigger: 'change' }],
}
export default function Demo() {
const [formData, setFormData] = useState<FormData>({ name: '', style: '' })
const formRef = useRef<LhFormInstance>(null)
const handleSubmit = async () => {
const valid = await formRef.current?.validate()
if (valid) alert(`送信成功:${formData.name} / ${formData.style}`)
}
const handleReset = () => {
formRef.current?.resetFields()
setFormData({ name: '', style: '' })
}
return (
<LhForm ref={formRef} model={formData} rules={rules} labelWidth="80px">
<LhFormItem label="作品名" prop="name">
<LhInput
value={formData.name}
onChange={(val) => setFormData((prev) => ({ ...prev, name: val }))}
/>
</LhFormItem>
<LhFormItem label="画風" prop="style">
<LhSelect
value={formData.style}
onChange={(val) => setFormData((prev) => ({ ...prev, style: val as string }))}
options={[{ label: '水墨', value: 'ink' }]}
/>
</LhFormItem>
<LhFormItem>
<LhButton type="primary" onClick={handleSubmit}>送信</LhButton>
<LhButton onClick={handleReset}>リセット</LhButton>
</LhFormItem>
</LhForm>
)
}
Form Props
| プロパティ | 説明 | 型 | デフォルト値 |
|---|---|---|---|
| model | フォームデータオブジェクト(必須) | Record<string, unknown> | — |
| rules | バリデーションルール。キーはフィールド名 | Record<string, LhFormRule[]> | — |
| labelWidth | ラベルの幅 | string | number | — |
| labelPosition | ラベルの位置 | 'left' | 'right' | 'top' | 'right' |
| inline | インラインレイアウト | boolean | false |
| disabled | すべての子項目を無効化 | boolean | false |
| size | 子項目のサイズ | 'large' | 'middle' | 'small' | ConfigProvider に準拠 |
| onSubmit | ネイティブ送信イベント(preventDefault 済み) | (event: FormEvent) => void | — |
FormItem Props
| プロパティ | 説明 | 型 | デフォルト値 |
|---|---|---|---|
| label | ラベルテキスト | string | — |
| prop | フィールド名(ドットパスをサポート。model のキーに対応) | string | — |
| rules | item レベルのルール(同名の場合は form レベルを上書き) | LhFormRule[] | — |
| required | 必須の星印(マークの描画のみ。バリデーション semantics は rules が提供) | boolean | false |
| labelWidth | form レベルのラベル幅を上書き | string | number | — |
| errorMessage | カスタムエラーメッセージ | string | — |
| showMessage | エラー通知を表示 | boolean | true |
LhFormRule
| プロパティ | 説明 | 型 |
|---|---|---|
| required | 必須かどうか | boolean |
| message | バリデーション失敗時のメッセージ | string |
| trigger | トリガー方式 | 'blur' | 'change' |
| validator | カスタムバリデーション関数(Promise を返せる。非同期バリデーションは正しく待機する) | (value, model) => string | undefined | Promise<string | undefined> |
| min / max | 最小 / 最大値(数値または長さ) | number |
| pattern | 正規表現によるバリデーション | RegExp |
Form ref メソッド
LhFormInstance(forwardRef + useImperativeHandle で公開):
| メソッド | 説明 | 戻り値 |
|---|---|---|
| validate | 全フィールドをバリデーション | Promise<boolean> |
| validateField | 単一フィールドをバリデーション | Promise<boolean> |
| resetFields | 全フィールドを初期値にリセット | void |
| resetField | 単一フィールドをリセット | void |
const formRef = useRef<LhFormInstance>(null)
const ok = await formRef.current?.validate()
本ライブラリはplus の非同期バリデーションの欠陥を修正しています:plus の validateField は Promise.resolve(!message) を使い、非同期 validator の Promise を待機しないため、非同期バリデーションが常に true を返します。React 版は thenable の完成を明示的に待ってから判定します。詳しくは移行ガイドを参照してください。
LhFormItem は useEffect 内で form にバリデーターを登録し、アンマウント時に自動的に解除します。フィールドはあらかじめ rules に宣言しておく必要はありません —— rules になく model にあるフィールドの初期値は、登録時に補撮されます。
share の validateFormField は trigger を解釈せず、トリガーのタイミングはこのレイヤーが接続します:trigger: 'blur'(デフォルト)は
FormItem のフォーカス外れに従ってバリデーションし、trigger: 'change' は内容領域の change に従ってバリデーションします。trigger が未指定のルールは
フォーカス外れと validate() の時にのみ実行され、入力中に繰り返しエラーは出ません。
change バリデーションはモデルのスナップショットではなくイベント.target の新しい値を使います —— React の状態更新とイベントディスパッチは
同一タイミングで行われないため、モデルを読み返すと 1 拍遅れます。ネイティブコントロール(input / textarea / ネイティブ select)の change イベントは
内容領域にバブルした時にキャプチャされます。カスタムコントロールにはネイティブ change イベントがなく(LhSelect の項目クリックは click しか発生させない)、
FormItem コンテキストの validateChange(value) を使い、新しい値を能動的に渡してトリガーします。
resetFields() は model を初期値のスナップショットに戻すほか、内部 resetVersion をインクリメントし、各 FormItem が
バージョン変化を検知して自身のエラー状態をクリアします。外部の制御状態は別途同期が必要です(demo の
setFormData(initial) など) —— React は Vue の reactive なチェーンのように model を代わりに書き換えることはできません。
スタイル
import '@lh-ui/react/style/form'