やったこと
react hook formとyupについて
useFormContext
useFormContext フックは、入れ子になっているコンポーネントに対して、必要になる props を簡単に渡せるようにするために用意されています。 React の useContext フックと同じような用途です。
import React from "react";
import { useForm, FormProvider, useFormContext } from "react-hook-form";
export default function App() {
  const methods = useForm();
  const onSubmit = data => console.log(data);
  return (
    <FormProvider {...methods} > // pass all methods into the context
      <form onSubmit={methods.handleSubmit(onSubmit)}>
        <NestedInput />
        <input type="submit" />
      </form>
    </FormProvider>
  );
}
function NestedInput() {
  const { register } = useFormContext(); // retrieve all hook methods
  return <input {...register("test")} />;
}
useWatch
useWatch フックは、コンポーネント単位の更新をおこないます。対象のコンポーネントに useForm フックの control を渡すことで、そのコンポーネントで useWatch フックの監視機能を使えるようになります。
import React from "react";
import { useForm, useWatch } from "react-hook-form";
function Child({ control }) {
  const firstName = useWatch({
    control,
    name: "firstName",
  });
  return <p>Watch: {firstName}</p>;
}
function App() {
  const { register, control } = useForm({
    firstName: "test"
  });
  
  return (
    <form>
      <input {...register("firstName")} />
      <Child control={control} />
    </form>
  );
}
useFormState
useFormState フックは、それぞれのフォームの状態を取得できます。 useFormState フックは、他の useFormState フックや useForm フックに干渉しないので、意図しない再レンダリングを予防できます。
import * as React from "react";
import { useForm, useFormState } from "react-hook-form";
export default function App() {
  const { register, handleSubmit, control } = useForm({
    defaultValues: {
      firstName: "firstName"
    }
  });
  const { dirtyFields } = useFormState({
    control
  });
  const onSubmit = (data) => console.log(data);
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("firstName")} placeholder="First Name" />
      {dirtyFields.firstName && <p>Field is dirty.</p>}
      
      <input type="submit" />
    </form>
  );
}
useFieldArray
useFieldArray フックは、制御されていないフィールドの配列として取り扱えます。また、配列に対して操作できる各種メソッドを取得できます。
useFieldArray フックを機能させるには、 useuseForm フックによって取得できる control オブジェクトを引数として設定する必要があります。
function FieldArray() {
  const { control, register } = useForm();
  const { fields, append, prepend, remove, swap, move, insert } = useFieldArray({
    control, // control props comes from useForm (optional: if you are using FormContext)
    name: "test", // unique name for your Field Array
  });
  return (
    {fields.map((field, index) => (
      <input
        key={field.id} // important to include key with field's id
        {...register(`test.${index}.value`)} 
      />
    ))}
  );
}
Yup
Killer Features:
- Concise yet expressive schema interface, equipped to model simple to complex data models
 - Powerful TypeScript support. Infer static types from schema, or ensure schema correctly implement a type
 - Built-in async validation support. Model server-side and client-side validation equally well
 - Extensible: add your own type-safe methods and schema
 - Rich error details, make debugging a breeze
 
↓ 翻訳
- シンプルなデータモデルから複雑なデータモデルまで対応可能な、簡潔かつ表現力豊かなスキーマインターフェイス。
 - TypeScriptを強力にサポート。スキーマから静的な型を推論したり、スキーマが正しく型を実装していることを確認することができます。
 - 非同期検証をサポート。サーバーサイドとクライアントサイドの検証を同じようにモデル化します。
 - 拡張性:独自のタイプセーフなメソッドやスキーマを追加可能
 - 豊富なエラーの詳細、デバッグを容易にします。
 
Getting Started
import { object, string, number, date, InferType } from 'yup';
let userSchema = object({
  name: string().required(),
  age: number().required().positive().integer(),
  email: string().email(),
  website: string().url().nullable(),
  createdOn: date().default(() => new Date()),
});
// parse and assert validity
const user = await userSchema.validate(await fetchUser());
type User = InferType<typeof userSchema>;
/* {
  name: string;
  age: number;
  email?: string | undefined
  website?: string | null | undefined
  createdOn: Date
}*/
Yup と React Hook Formの組み合わせ
import React from "react";
import { useForm } from "react-hook-form";
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from "yup";
interface IFormInputs {
  firstName: string
  age: number
}
const schema = yup.object().shape({
  firstName: yup.string().required(),
  age: yup.number().positive().integer().required(),
}).required();
export default function App() {
  const { register, handleSubmit, errors } = useForm<IFormInputs>({
    resolver: yupResolver(schema)
  });
  const onSubmit = (data: IFormInputs) => console.log(data);
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="firstName" ref={register} />
      <p>{errors.firstName?.message}</p>
        
      <input name="age" ref={register} />
      <p>{errors.age?.message}</p>
      
      <input type="submit" />
    </form>
  );
}