【Formik/Yup】React簡単フォーム作成ライブラリ解説

  • このエントリーをはてなブックマークに追加
  • Pocket

こんにちは。タクマ™ [@suwaru_blog] です。

最近 Next.js (React フレームワーク) を使っています。

React でフォーム作成するのは大変…

と聞いていましたが、ライブラリを使うとめっちゃ簡単でした!

今回、フォームコンポネント作成ライブラリ Formik と、
Validation ライブラリの Yup を使ったサンプルコードを公開します。

Formik / Yum インストール

yarn コマンドで必要なライブラリをインストールします。

cd [プロジェクト]

# formik と yup インストール
yarn add formik yup

Formik

Formik はフォームコンポネント作成ライブラリです。

Yup

Yup は Formik 公式でも推奨されている Validation 実装ライブラリです。

  • Formik と連携してバリデーションチェックしてくれます
  • Formik の validationSchema に Yup オブジェクトスキーマをセットします
    • handleSubmit の際、エラーがあると onSubmit を呼び出さないようにしてくれます
  • Yup は 非同期で動作します

公式ドキュメント

①お問い合わせフォーム → Slack 通知サンプル

  • 氏名
  • メールアドレス
  • 電話番号
  • お問い合わせ内容

上記項目の入力フォームです。送信すると Slack 通知するようにしています。

Slack にリクエストを投げるには yarn add axios をしておいてください。
Slack とかどうでもいい方は handleSubmit を空っぽにして好きな処理を記述してください。

import React, { Component } from 'react';
import axios from 'axios';
import Router from 'next/router';
import {
    Formik,
    Form,
    Field,
    ErrorMessage
} from 'formik';
import * as Yup from 'yup';

const phoneRegExp = /^((\\+[1-9]{1,4}[ \\-]*)|(\\([0-9]{2,3}\\)[ \\-]*)|([0-9]{2,4})[ \\-]*)*?[0-9]{3,4}?[ \\-]*[0-9]{3,4}?$/
const webhookURL = '[Slack の Webhook URL]';

/**
 * 非同期 Varidation
 */
const validationSchema = Yup.object().shape({
    name: Yup.string()
        .required('氏名は必須です'),
    email: Yup.string()
        .email('メールアドレスの形式に誤りがあります')
        .required('メールアドレスは必須です'),
    tel: Yup.string()
        .matches(phoneRegExp, '電話番号の形式に誤りがあります'),
    content: Yup.string()
        .required('お問い合わせ内容は必須です'),
});

class ContactForm extends Component {
    constructor(props) {
        super(props);
        this.defaultFormState = {
            name: '',
            email: '',
            tel: '',
            content: '',
        }
    }

    /**
     * フォーム送信後の処理
     */
    handleSubmit (form, { resetForm }) {
        let text = `■ 名前: ${form.name}\n■ メールアドレス: ${form.email}\n■ 電話番号: ${form.tel}\n■ お問い合わせ内容: ${form.content}`
        let data = {
            method: 'post',
            baseURL: webhookURL,
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            },
            data: `payload={ "text": "${ text }"}`
        };
        try {
            axios.request(data)
            alert('送信しました')
            resetForm()
            Router.push('/contact') // リダイレクト
        } catch (error) {
            alert('送信に失敗しました')
        }
    }

    render() {
        return (
            <Formik
                onSubmit={this.handleSubmit}
                initialValues={this.defaultFormState}
                validationSchema={validationSchema}
            >
                <Form>
                    <div className="form-field">
                        <Field
                            name="name"
                            type="text"
                            placeholder="氏名"
                        />
                    </div>
                    <div className="form-field">
                        <Field
                            name="email"
                            type="email"
                            placeholder="メールアドレス"
                        />
                    </div>
                    <div className="form-field">
                        <Field
                            name="tel"
                            type="tel"
                            placeholder="電話番号"
                        />
                    </div>
                    <div className="form-field">
                        <Field
                            name="content"
                            component="textarea"
                            placeholder="お問い合わせ内容"
                        />
                    </div>
                    <div className="form-field">
                        <button type="submit">
                            送信
                        </button>
                    </div>
                    <ErrorMessage
                        name="name"
                        component="div"
                        className="invalidForm"
                    />
                    <ErrorMessage
                        name="email"
                        component="div"
                        className="invalidForm"
                    />
                    <ErrorMessage
                        name="tel"
                        component="div"
                        className="invalidForm"
                    />
                    <ErrorMessage
                        name="content"
                        component="div"
                        className="invalidForm"
                    />
                </Form>
            </Formik>
        )
    }
}

export default ContactForm;

弊社のお問い合わせフォーム (https://eeeeg.tokyo/contact) はほとんど同じソースコードです。

②アカウント作成フォームサンプル

  • 氏名
  • メールアドレス
  • パスワード
  • パスワード再入力

上記項目の入力フォームです。

import React, { Component } from 'react';
import {
    Formik,
    Form,
    Field,
    ErrorMessage
} from 'formik';
import * as Yup from 'yup';

/**
 * 非同期 Varidation
 */
const validationSchema = Yup.object().shape({
    email: Yup.string()
        .email('メールアドレスの形式に誤りがあります')
        .required('メールアドレスは必須です'),
    password: Yup.string()
        .required('パスワード設定は必須です'),
    confirmPassword: Yup.string()
        .required('設定したパスワードを再入力してください')
        .oneOf([Yup.ref('password')], 'パスワードが一致しません')
});

class RegistrationForm extends Component {
    constructor(props) {
        super(props);
        this.defaultFormState = {
            email: '',
            password: '',
            confirmPassword: ''
        }
    }

    /**
     * フォーム送信後の処理
     */
    handleSubmit (form) {
        // 値をコンソール表示
        console.log(form)
    }

    render() {
        return (
            <Formik
                onSubmit={this.handleSubmit}
                initialValues={this.defaultFormState}
                validationSchema={validationSchema}
            >
                <Form>
                    <Field
                        name="email"
                        type="email"
                        placeholder="Email"
                    />
                    <Field
                        name="password"
                        type="password"
                        placeholder="Password"
                    />
                    <Field
                        name="confirmPassword"
                        type="password"
                        placeholder="Confirm password"
                    />
                    <button type="submit">
                        Submit
                    </button>
                    <ErrorMessage
                        name="email"
                        component="div"
                        className="invalidForm"
                    />
                    <ErrorMessage
                        name="password"
                        component="div"
                        className="invalidForm"
                    />
                    <ErrorMessage
                        name="confirmPassword"
                        component="div"
                        className="invalidForm"
                    />
                </Form>
            </Formik>
        )
    }
}

export default RegistrationForm;

(おまけ) handleSubmit 内で setState できない問題

フォーム送信したことを state 管理しようと思ったのですが、
handleSubmit() 内で setState を実行することはできませんでした…

Formik は結果ステータスを props で渡すことができるみたいなので、
それで上手いことやる必要がありそうです。

関連記事

関連記事

お仕事ください!

僕が代表を務める 株式会社 EeeeG では Web 制作・システム開発・マーケティング相談を行っています。
なにかお困りごとがあれば、Twitter DM や Web サイトからお気軽にご相談ください。

コメントを残す

*