Use Cases

React Hook Form com Claude Code

Aprenda sobre react hook form usando o Claude Code. Dicas praticas e exemplos de codigo incluidos.

React Hook Formでハイパフォーマンスなフォームを構築する

React Hook Formは非制御コンポーネントベースのフォームライブラリで、レンダリング回数を最小限に抑えた高速なフォームを構築できます。Claude Codeを使えば、複雑なフォーム設計も素早く実装可能です。

基本的なフォーム構成

Claude Codeにフォーム全体の設計を依頼しましょう。

> React Hook FormとZodで問い合わせフォームを作成して。
> 名前、メール、カテゴリ選択、本文を含めて。エラー表示もつけて。
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";

const contactSchema = z.object({
  name: z.string().min(1, "お名前を入力してください"),
  email: z.string().email("有効なメールアドレスを入力してください"),
  category: z.enum(["general", "support", "billing", "other"], {
    errorMap: () => ({ message: "カテゴリを選択してください" }),
  }),
  message: z
    .string()
    .min(10, "本文は10文字以上で入力してください")
    .max(2000, "本文は2000文字以内で入力してください"),
});

type ContactFormData = z.infer<typeof contactSchema>;

function ContactForm() {
  const {
    register,
    handleSubmit,
    formState: { errors, isSubmitting },
    reset,
  } = useForm<ContactFormData>({
    resolver: zodResolver(contactSchema),
    defaultValues: {
      category: undefined,
    },
  });

  const onSubmit = async (data: ContactFormData) => {
    await sendContactForm(data);
    reset();
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label htmlFor="name">お名前</label>
        <input id="name" {...register("name")} />
        {errors.name && <p role="alert">{errors.name.message}</p>}
      </div>

      <div>
        <label htmlFor="email">メールアドレス</label>
        <input id="email" type="email" {...register("email")} />
        {errors.email && <p role="alert">{errors.email.message}</p>}
      </div>

      <div>
        <label htmlFor="category">カテゴリ</label>
        <select id="category" {...register("category")}>
          <option value="">選択してください</option>
          <option value="general">一般</option>
          <option value="support">サポート</option>
          <option value="billing">請求</option>
          <option value="other">その他</option>
        </select>
        {errors.category && <p role="alert">{errors.category.message}</p>}
      </div>

      <div>
        <label htmlFor="message">本文</label>
        <textarea id="message" rows={5} {...register("message")} />
        {errors.message && <p role="alert">{errors.message.message}</p>}
      </div>

      <button type="submit" disabled={isSubmitting}>
        {isSubmitting ? "送信中..." : "送信"}
      </button>
    </form>
  );
}

動的フィールド(useFieldArray)

可変数のフィールドを管理するパターンです。

import { useForm, useFieldArray } from "react-hook-form";

interface InvoiceForm {
  clientName: string;
  items: {
    description: string;
    quantity: number;
    unitPrice: number;
  }[];
  notes: string;
}

function InvoiceForm() {
  const { register, control, handleSubmit, watch } = useForm<InvoiceForm>({
    defaultValues: {
      items: [{ description: "", quantity: 1, unitPrice: 0 }],
    },
  });

  const { fields, append, remove } = useFieldArray({
    control,
    name: "items",
  });

  const watchItems = watch("items");
  const total = watchItems.reduce(
    (sum, item) => sum + (item.quantity || 0) * (item.unitPrice || 0),
    0
  );

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("clientName")} placeholder="クライアント名" />

      {fields.map((field, index) => (
        <div key={field.id}>
          <input
            {...register(`items.${index}.description`)}
            placeholder="品目"
          />
          <input
            type="number"
            {...register(`items.${index}.quantity`, { valueAsNumber: true })}
          />
          <input
            type="number"
            {...register(`items.${index}.unitPrice`, { valueAsNumber: true })}
          />
          <button type="button" onClick={() => remove(index)}>
            削除
          </button>
        </div>
      ))}

      <button
        type="button"
        onClick={() => append({ description: "", quantity: 1, unitPrice: 0 })}
      >
        品目を追加
      </button>

      <p>合計: ¥{total.toLocaleString()}</p>
      <button type="submit">保存</button>
    </form>
  );
}

マルチステップフォーム

ウィザード形式のフォームもClaude Codeで効率的に実装できます。

import { useForm, FormProvider, useFormContext } from "react-hook-form";

interface MultiStepFormData {
  // Step 1
  firstName: string;
  lastName: string;
  email: string;
  // Step 2
  company: string;
  role: string;
  // Step 3
  plan: "free" | "pro" | "enterprise";
  agreeToTerms: boolean;
}

function MultiStepForm() {
  const [step, setStep] = useState(1);
  const methods = useForm<MultiStepFormData>({
    mode: "onChange",
  });

  const next = async () => {
    const fieldsToValidate = getFieldsByStep(step);
    const isValid = await methods.trigger(fieldsToValidate);
    if (isValid) setStep((s) => s + 1);
  };

  const prev = () => setStep((s) => s - 1);

  return (
    <FormProvider {...methods}>
      <form onSubmit={methods.handleSubmit(onSubmit)}>
        {step === 1 && <PersonalInfoStep />}
        {step === 2 && <CompanyInfoStep />}
        {step === 3 && <PlanSelectionStep />}

        <div>
          {step > 1 && <button type="button" onClick={prev}>戻る</button>}
          {step < 3 ? (
            <button type="button" onClick={next}>次へ</button>
          ) : (
            <button type="submit">完了</button>
          )}
        </div>
      </form>
    </FormProvider>
  );
}

function PersonalInfoStep() {
  const { register, formState: { errors } } = useFormContext<MultiStepFormData>();
  return (
    <div>
      <input {...register("firstName", { required: "必須項目です" })} />
      <input {...register("lastName", { required: "必須項目です" })} />
      <input {...register("email", { required: "必須項目です" })} />
    </div>
  );
}

カスタムフィールドコンポーネント

再利用可能なフィールドコンポーネントを設計するパターンです。

import { Controller, useFormContext, FieldPath } from "react-hook-form";

interface FormFieldProps<T extends Record<string, any>> {
  name: FieldPath<T>;
  label: string;
  type?: "text" | "email" | "number" | "textarea";
  placeholder?: string;
}

function FormField<T extends Record<string, any>>({
  name,
  label,
  type = "text",
  placeholder,
}: FormFieldProps<T>) {
  const { register, formState: { errors } } = useFormContext<T>();
  const error = errors[name];

  return (
    <div className="form-field">
      <label htmlFor={name}>{label}</label>
      {type === "textarea" ? (
        <textarea id={name} {...register(name)} placeholder={placeholder} />
      ) : (
        <input id={name} type={type} {...register(name)} placeholder={placeholder} />
      )}
      {error && <p className="error">{error.message as string}</p>}
    </div>
  );
}

Summary

React Hook Formは非制御コンポーネントベースのアプローチにより、大規模なフォームでも優れたパフォーマンスを発揮します。Claude Codeを活用すれば、バリデーション統合、動的フィールド、マルチステップフォームなどの複雑なパターンも短時間で実装可能です。

バリデーションの詳細はZodバリデーション実践ガイドを、UIコンポーネントとの統合はRadix UIコンポーネント活用を参照してください。React Hook Form公式ドキュメントも確認しておきましょう。

#Claude Code #React Hook Form #React #forms #validation