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


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

Formikとは?

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

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

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のバリューやイベントを設定

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

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

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

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

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

MaterialUIでの使い方

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

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]}
    ~~
  />
};