⚛️

formikとyupでReactのFormを作成

8 min read

概要

formik を使って、React の form を作成方法についてまとめます。

formik は React で Form を作成するときに便利なライブラリです。
初期値やバリデーションを React らしく作成することが可能です。
また Yup というバリデーションを簡潔に記述できるライブラリをサポートしており、組み合わせることで直感的な Form 作成を実現できます。

formik はチュートリアル(リンク)がとてもわかりやすいので、そちらをお勧めします。
本記事もチュートリアルの内容を参考にしてソースコードを記述します。

本記事のサンプルコードは以下です。

https://github.com/Msksgm/react-formik-example

実装

formik にはuseFormikFormikを用いた記述方法があります。
useFormikは Hooks を使用した実装方法で、Formikは API コンポーネントを使用した実装方法です。

useFormik Yup なし

useFormik を用いたときのサンプルコードです。

引数にinitialValues(初期値)、validate(バリデーション)、onSubmit(クリック時の挙動)を渡します。
validateは Yup を使わないと関数(最大値、最小値、有効な文字、エラーメッセージなど)を自作することになります。

import { FC } from "react";
import { useFormik } from "formik";

type valuesType = {
  firstName: string;
  lastName: string;
  email: string;
};

type errorsType = {
  firstName?: string;
  lastName?: string;
  email?: string;
};

const validate = (values: valuesType) => {
  const errors: errorsType = {};

  if (!values.firstName) {
    errors.firstName = "Required";
  } else if (values.firstName.length > 15) {
    errors.firstName = "Must be 15 characters or less";
  }

  if (!values.lastName) {
    errors.lastName = "Required";
  } else if (values.lastName.length > 20) {
    errors.lastName = "Must be 20 characters or less";
  }

  if (!values.email) {
    errors.email = "Required";
  } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
    errors.email = "Invalid email address";
  }

  return errors;
};

const SignupForm: FC = () => {
  const formik = useFormik({
    initialValues: {
      firstName: "",
      lastName: "",
      email: "",
    },
    validate,
    onSubmit: (values) => {
      alert(JSON.stringify(values, null, 2));
    },
  });
  return (
    <form onSubmit={formik.handleSubmit}>
      <div>
        <label htmlFor="firstName">First Name</label>
        <input
          id="firstName"
          name="firstName"
          type="text"
          onChange={formik.handleChange}
          onBlur={formik.handleBlur}
          value={formik.values.firstName}
        />
        {formik.touched.firstName && formik.errors.firstName ? (
          <div>{formik.errors.firstName}</div>
        ) : null}
      </div>

      <div>
        <label htmlFor="lastName">Last Name</label>
        <input
          id="lastName"
          name="lastName"
          type="text"
          onChange={formik.handleChange}
          onBlur={formik.handleBlur}
          value={formik.values.lastName}
        />
        {formik.touched.lastName && formik.errors.lastName ? (
          <div>{formik.errors.lastName}</div>
        ) : null}
      </div>

      <div>
        <label htmlFor="email">Email Address</label>
        <input
          id="email"
          name="email"
          type="email"
          onChange={formik.handleChange}
          onBlur={formik.handleBlur}
          value={formik.values.email}
        />
        {formik.touched.email && formik.errors.email ? (
          <div>{formik.errors.email}</div>
        ) : null}
      </div>

      <button type="submit">Submit</button>
    </form>
  );
};

export default SignupForm;

useFormik Yup あり

useFormikYup を組み合わせたときのサンプルコードです。

引数のvalidationvalidationSchemaに変更され、Yupオブジェクトを直接渡すことが可能です。
バリデーションを自作するよりも簡潔に記述することができるようになりました。

import { FC } from "react";
import { useFormik } from "formik";
import * as Yup from "yup";

const SignupForm: FC = () => {
  const formik = useFormik({
    initialValues: {
      firstName: "",
      lastName: "",
      email: "",
    },
    validationSchema: Yup.object({
      firstName: Yup.string()
        .max(15, "Must be 15 characters or less")
        .required("Required"),
      lastName: Yup.string()
        .max(20, "Must be 20 characters or less")
        .required("Required"),
      email: Yup.string().email("Invalid email address").required("Required"),
    }),
    onSubmit: (values) => {
      alert(JSON.stringify(values, null, 2));
    },
  });
  return (
    <form onSubmit={formik.handleSubmit}>
      <label htmlFor="firstName">First Name</label>
      <input
        id="firstName"
        name="firstName"
        type="text"
        onChange={formik.handleChange}
        onBlur={formik.handleBlur}
        value={formik.values.firstName}
      />
      {formik.touched.firstName && formik.errors.firstName ? (
        <div>{formik.errors.firstName}</div>
      ) : null}

      <label htmlFor="lastName">Last Name</label>
      <input
        id="lastName"
        name="lastName"
        type="text"
        onChange={formik.handleChange}
        onBlur={formik.handleBlur}
        value={formik.values.lastName}
      />
      {formik.touched.lastName && formik.errors.lastName ? (
        <div>{formik.errors.lastName}</div>
      ) : null}

      <label htmlFor="email">Email Address</label>
      <input
        id="email"
        name="email"
        type="email"
        onChange={formik.handleChange}
        onBlur={formik.handleBlur}
        value={formik.values.email}
      />
      {formik.touched.email && formik.errors.email ? (
        <div>{formik.errors.email}</div>
      ) : null}

      <button type="submit">Submit</button>
    </form>
  );
};

export default SignupForm;

Formik Yup あり

Formikを用いたサンプルコードです。
FieldFormErrorMessageといった関数も formik に用意されており、これらを組み合わせることでuseFormikを使うよりもさらに簡潔に書くことが可能です。

import { FC } from "react";
import { Formik, Field, Form, ErrorMessage } from "formik";
import * as Yup from "yup";

const SignupForm: FC = () => {
  return (
    <Formik
      initialValues={{ firstName: "", lastName: "", email: "" }}
      validationSchema={Yup.object({
        firstName: Yup.string()
          .max(15, "Must be 15 characters or less")
          .required("Required"),
        lastName: Yup.string()
          .max(20, "Must be 20 characters or less")
          .required("Required"),
        email: Yup.string().email("Invalid email address").required("Required"),
      })}
      onSubmit={(values, { setSubmitting }) => {
        setTimeout(() => {
          alert(JSON.stringify(values, null, 2));
          setSubmitting(false);
        }, 400);
      }}
    >
      <Form>
        <div>
          <label htmlFor="firstName">First Name</label>
          <Field name="firstName" type="text" />
          <ErrorMessage name="firstName" />
        </div>

        <div>
          <label htmlFor="lastName">Last Name</label>
          <Field name="lastName" type="text" />
          <ErrorMessage name="lastName" />
        </div>

        <div>
          <label htmlFor="email">Email Address</label>
          <Field name="email" type="email" />
          <ErrorMessage name="email" />
        </div>

        <button type="submit">Submit</button>
      </Form>
    </Formik>
  );
};

export default SignupForm;

動作確認

実行

git clone https://github.com/Msksgm/react-formik-example.git
cd react-formik-example
yarn
yarn start

画面

localhost:3000に以下のような画面が表示されます。
すべての Form が同じ動作をしますが、<Formik />を使用することでソースコードの記述量が激減します。
なので、保守性の観点も含めて、formik を使うときには<Formik />を使うようにしています。
checkbox を使うときの書き方もチュートリアルに記述してあるので参考にしてみてください。


localhost3000

参考

https://formik.org/docs/tutorial

Discussion

ログインするとコメントできます