2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MantineのuseFormでReactフォームを管理する

Posted at

基本の使い方

Mantine の useForm は、フォームのバリデーション、初期値設定、値の変更トラッキング、エラー管理を簡潔に実装できるフックです。

import { useForm } from '@mantine/form';

const form = useForm({
  initialValues: {
    email: '',
    password: '',
  },

  validate: {
    email: (value) => (/^\S+@\S+$/.test(value) ? null : '無効なメールアドレス'),
    password: (value) =>
      value.length >= 6 ? null : 'パスワードは6文字以上である必要があります',
  },
});

各部分の解説

import { useForm } from '@mantine/form'

  • Mantine が提供する useForm フックをインポートします。

const form = useForm({ ... })

  • useForm を呼び出すと、「フォームの状態や操作を管理するオブジェクト」が返ってきます。
  • 返される form はオブジェクトで、値・エラー・バリデーション・イベント処理関数などが入っています。

initialValues

initialValues: {
  email: '',
  password: '',
}
  • フォームの初期値を設定します。
  • form.values.emailform.values.password にこの値が入ります。
  • <input {...form.getInputProps("email")} /> などでこれらの値がバインドされます。

validate

validate: {
  email: (value) => (/^\S+@\S+$/.test(value) ? null : '無効なメールアドレス'),
  password: (value) => value.length >= 6 ? null : 'パスワードは6文字以上である必要があります',
}
  • 各フィールドのバリデーション関数を定義します。
  • 関数は null を返せば「OK」、エラーメッセージ文字列を返すと「エラー」扱いになります。
  • form.validate()form.onSubmit() のときに実行されます。

イメージとしては…

const form = {
  values: { ... },            // 各フィールドの現在の値
  errors: { ... },            // 各フィールドのバリデーションエラー
  setFieldValue: fn(),        // 値をプログラムで更新
  validate: fn(),             // バリデーションを実行
  getInputProps: fn(),        // 各inputに必要なpropsを生成
  onSubmit: fn(),             // submitイベントをラップ
  reset: fn(),                // 初期状態にリセット
  ... そのほか
}

つまり、form = 「フォームの操作・情報が詰まった道具箱」という感覚です。

よくあるユースケース

ユースケース1:ログインフォーム

要件

  • ユーザーがメールアドレスとパスワードを入力
  • バリデーションが必要(メール形式、パスワード6文字以上)

実装

import { TextInput, Button } from '@mantine/core';
import { useForm } from '@mantine/form';

function LoginForm() {
  const form = useForm({
    initialValues: {
      email: '',
      password: '',
    },
    validate: {
      email: (value) => (/^\S+@\S+$/.test(value) ? null : '無効なメールアドレス'),
      password: (value) =>
        value.length >= 6 ? null : 'パスワードは6文字以上である必要があります',
    },
  });

  const handleLogin = (values: typeof form.values) => {
    console.log('ログイン処理:', values);
    // API へログインリクエスト送信など
  };

  return (
    <form onSubmit={form.onSubmit(handleLogin)}>
      <TextInput label="メールアドレス" {...form.getInputProps('email')} />
      <TextInput label="パスワード" type="password" {...form.getInputProps('password')} />
      <Button type="submit">ログイン</Button>
    </form>
  );
}

ユースケース2:プロフィール編集フォーム(APIと連携)

要件

  • ユーザー名、年齢を編集可能
  • フォーム初期値は API から取得してセット
  • 年齢は数値として扱う(文字列→数値変換あり)

実装例

import { TextInput, Button, NumberInput } from '@mantine/core';
import { useForm } from '@mantine/form';
import { useEffect } from 'react';

function ProfileForm() {
  const form = useForm({
    initialValues: {
      name: '',
      age: 0,
    },
    validate: {
      name: (value) => (value ? null : '名前は必須です'),
      age: (value) => (value > 0 ? null : '年齢は正の数である必要があります'),
    },
  });

  // ダミーAPI呼び出し
  useEffect(() => {
    fetch('/api/me')
      .then((res) => res.json())
      .then((data) => {
        form.setValues({
          name: data.name,
          age: data.age,
        });
      });
  }, []);

  const handleSubmit = (values: typeof form.values) => {
    console.log('更新データ:', values);
    // PUT /api/me に送信など
  };

  return (
    <form onSubmit={form.onSubmit(handleSubmit)}>
      <TextInput label="名前" {...form.getInputProps('name')} />
      <NumberInput label="年齢" {...form.getInputProps('age')} />
      <Button type="submit">更新</Button>
    </form>
  );
}

ユースケース3:チェックボックス付きの同意フォーム

要件

  • 規約に同意したらボタンが有効になる

実装例

import { Checkbox, Button } from '@mantine/core';
import { useForm } from '@mantine/form';

function ConsentForm() {
  const form = useForm({
    initialValues: {
      agreed: false,
    },
    validate: {
      agreed: (value) => (value ? null : '同意が必要です'),
    },
  });

  return (
    <form onSubmit={form.onSubmit((v) => console.log(v))}>
      <Checkbox label="利用規約に同意します" {...form.getInputProps('agreed', { type: 'checkbox' })} />
      <Button type="submit" disabled={!form.values.agreed}>送信</Button>
    </form>
  );
}

知識ポイントまとめ

ポイント 説明 補足
form.getInputProps('name') <input>value, onChange, error などを自動付与 ほぼ必須の使い方。これでフォームと状態が連携される
form.values フォームの全フィールドの現在の値 送信時やログ出力に使う
form.errors 各フィールドのバリデーションエラー(あれば) UIでエラー表示に使える
form.validate() 現在の状態に対して全体バリデーションを実行 手動でバリデーションしたいときに使う
form.setFieldValue('field', value) 特定フィールドの値をプログラムで変更 APIや副作用から値をセットするときに使う
form.setValues({...}) 複数フィールドをまとめて更新 APIから初期値をセットするときに便利
form.reset() 初期状態に戻す 編集フォームのキャンセルなどで使用
form.onSubmit(handler) <form>onSubmit に渡す用のハンドラ バリデーション付きで安全な送信を実現

useForm は「Reactの状態管理」と「フォームのバリデーション・入力UI」を自動でつなげてくれる仕組み


よくある落とし穴・注意点

1. getInputProps使う型に合わせて指定が必要

例:

<Checkbox {...form.getInputProps('agreed', { type: 'checkbox' })} />

落とし穴:

<Checkbox {...form.getInputProps('agreed')} /> // ← これだと `true/false` が効かない

type: 'checkbox' を明示しないと、value が正しく動作しない。

2. initialValues の値の型が実際の UI と一致していないとエラーや不具合になる

例:

initialValues: { age: 0 }
// 実際は TextInput を使っていて、文字列になる → バリデーションで型がずれる

対策:

  • NumberInputSelect を使うときは型を合わせるか、バリデーションや onChange で型変換を明示的にする

3. form.validate()フィールドごとのバリデーション関数に依存

  • フィールドが validate に定義されていないと、チェックされない
  • 逆に、不要なフィールドに validate を残すと無意味にバリデーションされる

対策:validate オブジェクトは使っているフィールドだけにする

4. form.reset() は初期値に戻すだけ。現在の値は保存されない

  • 「編集を一時保存 → リセットで戻す」ような挙動を想定してると意図とズレる

対策:form.values をコピーして退避しておくなどで対応

5. getInputProps() を使わずに value, onChange を手動管理しようとすると混乱しやすい

例:

<input value={form.values.name} onChange={(e) => setSomething(e.target.value)} />

useForm の状態と同期しなくなり、フォームが壊れることがある

対策:基本的にはすべて getInputProps() に任せる

6. validateInputOnChange, validateInputOnBlur の動作を把握していないと混乱する

  • デフォルトでは、バリデーションは submit 時だけ
  • validateInputOnBlur: true を設定すると blur 時にバリデーションされる

明示的に動作を設定した方が、意図通りに動きやすい

const form = useForm({
  initialValues: { name: '' },
  validate: { ... },
  validateInputOnBlur: true, // 入力欄を離れたときにチェック
});

まとめ

useForm は、React のフォーム管理をシンプルかつ直感的にする強力なフック
useForm = React における「フォーム状態・バリデーション・イベント」のすべてを一元管理するハブ

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?