search
LoginSignup
13

More than 1 year has passed since last update.

posted at

updated at

Formikで利用する場合のYupのカスタマイズ

はじめに

今まで react-redux-formを使ってたのですが、公式からもう使うなって言われてしまったのでFormikに書き換えてみました。その際バリデーションのコントロールを行う為にYupをカスタマイズしたのでその内容をメモしておきます。Formikでの具体的なYupの利用方法はここでは記載しません。

カスタマイズの基本

yup.custom.js
import * as Yup from 'yup';

//カスタマイズを記述

export default Yup;

で、yupを利用するときにはこのカスタマイズファイルを利用します。

import Yup from '/path/to/yup.custom.js';

日本語化

公式サンプルだとTypeScriptなんですよね。

Yup.setLocale({
  mixed: {
    default: '入力エラーです',
    required: '必須入力項目です',
    oneOf: ({ values }) => `次の値のいずれかでなければなりません: ${values}`,
    notOneOf: ({ values }) => `次の値のいずれかであってはなりません: ${values}`,
    notType: '形式が違います',
  },
  string: {
    length: ({ length }) => `${length}文字入力して下さい`,
    min: ({ min }) => `${min}文字以上入力してください`,
    max: ({ max }) => `${max}文字以内で入力して下さい`,
    matches: '形式が違います',
    email: '形式が違います',
    url: '形式が違います',
    trim: '前後にスペースを入れてはいけません',
    lowercase: '小文字でなければなりません',
    uppercase: '大文字でなければなりません',
  },
  number: {
    min: ({ min }) => `${min}以上の値を入力して下さい`,
    max: ({ max }) => `${max}以下の値を入力して下さい`,
    lessThan: ({ lessThan }) => `${lessThan}より小さい値を入力して下さい`,
    moreThan: ({ moreThan }) => `${moreThan}より大きい値を入力して下さい`,
    notEqual: ({ notEqual }) => `${notEqual}と違う値を入力して下さい`,
    positive: '正の数を入力して下さい',
    negative: '負の数を入力して下さい',
    integer: '整数を入力して下さい',
  },
  date: {
    default: '形式が違います',
    min: ({ min }) => `${min}以上の日付を入力して下さい`,
    max: ({ max }) => `${max}以下の日付を入力して下さい`,
  },
  object: {
    noUnknown: '有効なキーを持ったデータを入力して下さい',
  },
  array: {
    min: ({ min }) => `${min}個以上の値を入力して下さい`,
    max: ({ max }) => `${max}個以下の値を入力して下さい`,
  },
});

引数として pathを取ると、例えば

length:({path,length}) =>`${path}には${length}文字入力して下さい`,

という記載ができるのですが、pathの値はそのままだと変数名ですので、label()関数を使って

Yup.object().shape({
  zipcode: Yup.string().label('郵便番号').length(7),
});

みたいな書き方が必要です。カスタマイズファイルの中でpath=>labelの変換なんかをしてみても面白そうです。

独自メソッドの追加

addMethod()test()関数を使います。

Yup.addMethod(Yup.string, 'katakana', function() {
  return this.test('katakana', 'カタカナで入力して下さい', function(value) {
    if (value == null || value === '') return true;
    return value.match(/^[ァ-ヶー  ]+$/);
  });
});
Yup.addMethod(Yup.string, 'unique', function(api) {
  return this.test('unique', '既に使用されています', function(value) {
    if (value == null || value === '') return true;
    return new Promise(resolve => {
      fetch(api + value).then(response => resolve(response.text === 'true'));
    });
  });
});

使うときは

Yup.string().katakana();
Yup.string().unique(apiPath);

のようになります。arrow functionを使うとthisを上書きしてしまいますので

  • this.path: 評価中の変数名
  • this.from: Yupオブジェクトがネストされている場合、親の情報が取得できる
  • this.createError(): 独自にエラーメッセージの作成ができる

等を利用したい場合は ()=>{}では無くfunction(){}を使いましょう。
addMethod()で追加した関数にもsetLocaleが使えれば良かったのですが、駄目みたいです。

変換について

このへんでも議論になっていますが、Formik で使う際に、Yup.cast() や、 Yup.tranform()による変換は基本的に動作しません。 自分はonSubmitの時に独自に変換していますが、どうしても使いたければ formik-yupを使いましょう。

その他

サンプルで書いた unique() なんかは<Formik />中でで利用していると、検証の対象外の入力フォームを操作していても動作しているみたいです。このあたり情報をお持ちでしたら誰か教えて下さい。

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
What you can do with signing up
13