LoginSignup
5
4

More than 5 years have passed since last update.

React ReduxのFormのライブラリを探す

Posted at

ReactでFormを作るのは、すごく面倒
React ReduxのFormライブラリを2つ試した。

redux-form
https://github.com/erikras/redux-form/issues/new

Formik
https://github.com/jaredpalmer/formik

redux-formは、onSubmit、handleSubmitの動きが気持ち悪るくて断念。

Formikは、わかりやすいが、連携するバリエーションライブラリのYupが癖がありそう。

例) Formik + Yup + Stripe

// @flow
import React from "react";
import { CardElement, injectStripe } from "react-stripe-elements";
import "./CheckoutForm.css";
import { Formik, Field, Form, ErrorMessage } from "formik";
import * as Yup from "yup";
import { setLocale } from "yup";
import { localeJP } from "../config/yup.locale.ja";
setLocale(localeJP);
const CheckoutSchema = Yup.object().shape({
  name: Yup.string()
    .min(2)
    .max(5)
    .required()
    .label("名前"),
  email: Yup.string()
    .email()
    .required()
    .label("メールアドレス"),
  tel: Yup.string()
    .min(2)
    .max(50)
    .required()
    .label("電話番号")
});

class CheckoutForm extends React.Component {
  render() {
    const { stripe, goto, saveInputData } = this.props;
    const { name, email, tel, card } = this.props.purchase;
    return (
      <Formik
        initialValues={{
          name,
          email,
          tel
        }}
        validationSchema={CheckoutSchema}
        onSubmit={(values, { setSubmitting }) => {
          stripe.createToken().then(({ token }) => {
            if (token) {
              console.log("Received Stripe token:", token);
              console.log("onSubmit:", values);

              saveInputData({
                ...values,
                card: token
              });
              setSubmitting(false);
              goto("/account/subscriptions/confirmation");
            } else {
              console.error("createToken エラー");
            }
          });
        }}
      >
        <Form className="example example1">
          <fieldset>
            <div className="row">
              <label htmlFor="example1-name">名前</label>
              <Field
                name="name"
                type="text"
                id="example1-name"
                placeholder="Jane Doe"
                required=""
                autoComplete="name"
              />
              <ErrorMessage name="name" component="span" />
            </div>
            <div className="row">
              <label htmlFor="example1-email">メールアドレス</label>
              <Field
                name="email"
                id="example1-email"
                type="email"
                placeholder="janedoe@gmail.com"
                required=""
                autoComplete="email"
              />
              <ErrorMessage name="email" component="span" />
            </div>

            <div className="row">
              <label htmlFor="example1-phone">電話番号</label>
              <Field
                name="tel"
                id="example1-phone"
                type="tel"
                placeholder="(941) 555-0123"
                required=""
                autoComplete="tel"
              />
              <ErrorMessage name="tel" component="span" />
            </div>
          </fieldset>
          <fieldset>
            <div className="row">
              {card && <div>**** - **** - ***** - {card.card.last4}</div>}

              {!card && (
                <CardElement
                  style={{
                    base: {},
                    invalid: {}
                  }}
                />
              )}
            </div>
          </fieldset>

          <button>購入する</button>
        </Form>
      </Formik>
    );
  }
}

export default injectStripe(CheckoutForm);

yupのバリデーションで、ラベルを日本語にするのにハマった。
こんな感じで、日本語ラベルを設定できる。

import * as Yup from "yup";
import { setLocale } from "yup";
import { localeJP } from "../config/yup.locale.ja";
setLocale(localeJP);
const CheckoutSchema = Yup.object().shape({
  name: Yup.string()
    .min(2)
    .max(5)
    .required()
    .label("名前"),
  email: Yup.string()
    .email()
    .required()
    .label("メールアドレス"),
  tel: Yup.string()
    .min(2)
    .max(50)
    .required()
    .label("電話番号")
});

あとは、setLocalを日本語訳する必要がある。↓


// @flow
/* eslint no-template-curly-in-string:0 */

export const localeJP = {
  mixed: {
    default: "${path} is invalid",
    required: "${path} is a required field",
    oneOf: "${path} must be one of the following values: ${values}",
    notOneOf: "${path} must not be one of the following values: ${values}"
  },
  string: {
    length: "${path} must be exactly ${length} characters",
    min: "${path} must be at least ${min} characters",
    max: "${path} must be at most ${max} characters",
    matches: '${path} must match the following: "${regex}"',
    email: "${path} must be a valid email",
    url: "${path} must be a valid URL",
    trim: "${path} must be a trimmed string",
    lowercase: "${path} must be a lowercase string",
    uppercase: "${path} must be a upper case string"
  },
  number: {
    min: "${path} must be greater than or equal to ${min}",
    max: "${path} must be less than or equal to ${max}",
    lessThan: "${path} must be less than ${less}",
    moreThan: "${path} must be greater than ${more}",
    notEqual: "${path} must be not equal to ${notEqual}",
    positive: "${path} must be a positive number",
    negative: "${path} must be a negative number",
    integer: "${path} must be an integer"
  },
  date: {
    min: "${path} field must be later than ${min}",
    max: "${path} field must be at earlier than ${max}"
  },
  object: {
    noUnknown:
      "${path} field cannot have keys not specified in the object shape"
  },
  array: {
    min: "${path} field must have at least ${min} items",
    max: "${path} field must have less than or equal to ${max} items"
  }
};

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4