Formikの基本的な使い方と、MaterialUIでの使用例

以前の案件で使ったFormikのメモです。
公式ドキュメントがやはり一番詳しいですが、
初めて使う人は簡単な概要があったほういいかもしれないので、記事にしておきます。

## Formikとは?
FormikはReactのフォームの扱いをシンプルにしてくれるライブラリです。

[Formik公式ドキュメント] (https://formik.org/docs/overview)
おそらく世界で一番使われているReactのフォームライブラリじゃないかなと思います。
npm trendsで他ライブラリと比較してみました。

![スクリーンショット 2021-07-30 0.02.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178099/f131be32-6ffd-055d-457a-d289bf92138b.png)

react-hook-formも伸びてきていますが、他ライブラリとかなり差が開いていますね。

Formikは以下3点を受け持ってくれます。

- formの状態管理
- バリデーション
- フォームのsubmit処理

フォームの状態管理にはRedux-Formというライブラリもありますが、
Formikの方がシンプルっぽいです。
Redux使うと、複雑になりやすいので、
Formikの方がいいケースの方が多いんじゃないかなと思います。

バリデーションについては、Yupというライブラリとセットで使うことが多いです。公式でもYupいいよね的なこと言ってますね。

## Formikの使い方概要

とりあえずインストールしましょう。

```
npm install formik --save
// または
yarn add formik
```

使い方は大きく分けて3種類あります。

- useFormikを使って書くやり方
- withForimikを使う書き方
- JSXのreturn部分で`<Formik>`コンポーネントを使って書いていくやり方

Formikコンポーネントを使って書いた方が簡潔にかけます。
一方、materialUIなどのコンポーネントで使う場合にはuseFormikを使うというやり方があります。

この記事ではuseFormikを使った記述内容中心にして、
別記事でFormikコンポーネントを使った方法を書いて行こうかなと思います。

ちなみにFormikコンポーネントはuseFormikを内部的に使っています。

## useFormikの使い方ざっくり

大体以下の感じになるかと思います。

- useFormikを使い、引数や型でフォームの情報を設定。
    - フォームで何を扱うかを型で設定
    - 初期値の設定
    - バリデーションの設定
    - formのonSubmit時の処理の設定
- formタグのonSubmitプロパティにformik.handleSubmitを設定
- 各フォーム要素にformikのバリューやイベントを設定

コードで書いてみると以下のような感じのサンプルに鳴ります。

```tsx
import { useFormik } from 'formik';
import * as Yup from 'yup';

const SampleComponent = () => {

  const formik = useFormik<Type>({
    // フォームに初期値を設定
    initialValues: {
      email: '',
      password: '',
    },
    // バリデーション
    validationSchema: validationSchema,
    // submit時のファンクション
    onSubmit: values => {
      // valuesはformの現在の値を返す。
      alert(JSON.stringify(values, null, 2))
    },
  });

  return (
    <form onSubmit={formik.handleSubmit}>
      <label htmlFor="email">Email Address</label>
      <input
        // idとnameをinitialValuesで設定したプロパティと合わせて設定
        id="email"
        name="email"
        type="email"
        onChange={formik.handleChange}
        onBlur={formik?.handleBlur}
        value={formik.values.email}
      >
      <label htmlFor="password">Password</label>
      {formik.errors.email ? <div>{formik.errors.email}</div> : null}

      <input
        id="password"
        name="password"
        type="password"
        onChange={formik.handleChange}
        onBlur={formik?.handleBlur}
        value={formik.values.password}
      >
      {formik.errors.password ? <div>{formik.errors.password}</div> : null}
      <button type="submit">Submit</button>
    </form>
  )
}

const SignupSchema = Yup.object().shape({
   email: Yup.string().email()
     .required('Required'),
   password: Yup.string()
     .min(2, 'Too Short!')
     .max(50, 'Too Long!')
     .required('Required'),
   email: Yup.string().email('Invalid email').required('Required'),
});

```

inputの設定プロパティが少し多い感じがしますね。
<Formik>タグを使うやり方であれば、もっとシンプルに書けます。

### よく使いそうなプロパティ

他にも色々とありますが、以下の3つはよく使いました。

```tsx
// 特定のフォーム要素に値を設定。
formik.setFieldValue('email', 'aaa@example.com')
// 複数のフォーム要素に値を設定。APIで取得した値を一括で設定したいときなどに利用
formik.setValues(values)
// フォームの値をリセット
formik.handleReset
```

## MaterialUIでの使い方

TextFieldやRadioButtonはアプリケーションの中でよくある要素なので、
コンポーネント分割されて使いまわされるケースが多いと思います。
そんな場合位はこんな感じにformikをpropsで渡してあげればいいです。

```tsx
interface Props {
	name: string;
  formik?: ReturnType<typeof useFormik>;
}

const TextFieldParts: FC<Props> = ({name, formik}) => {
  return <TextField
    ~~
    value={formik?.values[name]}
    onChange={formik?.handleChange}
    onBlur={formik?.handleBlur}
    error={Boolean(formik?.errors[name])}
    helperText={formik?.errors[name]}
    ~~
  />
};
```