くらげになりたい。

くらげのようにふわふわ生きたい日曜プログラマなブログ。趣味の備忘録です。

Vue3対応版のVee-Validate4がかなり変わっていた

Vee-Validate3を使ってたけど、Vue3を利用しているので、
Vue3対応版のVee-Validate4を試してみたときに備忘録。

かなり変わっているので、びっくりする(*´ω`*)

主な変更点

  • ValidationProviderなどで囲わなくなり、
    FormFieldなどのコンポーネントが提供されるようになった.
  • validationルールは提供されなり、
    Yupなどを使い自分で定義が必要に
  • フォームに全体のルールを設定できるようになり、
    フィールドごとにルールが不要になった。

使い方

まずはインストール。

$ npm install vee-validate --save

コンポーネント

フィールドのバリデーション

基本的には、提供されるコンポーネント<form><input>のように使う。
必須入力であっても、validationルールは自分で作る必要がある。
Form-level Validation

<template>
  <Form>
    <Field name="field" :rules="isRequired" />
    <ErrorMessage name="field" />
  </Form>
</template>

<script setup>
import { Field, Form, ErrorMessage } from 'vee-validate';

// validationルール: 必須
function isRequired(value) {
  if (value && value.trim()) {
    return true;
  }
  return 'This is required';
}
</script>

バリデーションライブラリのYupを使うと便利らしい。
jquense/yup: Dead simple Object schema validation

<template>
  <Form>
    <Field name="password" type="password" :rules="passwordRules" />
    <ErrorMessage name="password" />
  </Form>
</template>
<script setup>
import { Field, Form, ErrorMessage } from 'vee-validate';
import * as yup from 'yup';
const passwordRules = yup.string().required().min(8);
</script>

フォームレベルでのバリデーション

フィールド個別にバリデーションを書く必要がなくなったらしい。
各フィールドのルールを設定して、Formvalidation-schemaに設定すればよいよう。

Form-level Validation

<template>
  <Form @submit="submit" :validation-schema="schema">
    <Field name="email" />
    <ErrorMessage name="email" />
    
    <Field name="password" type="password" />
    <ErrorMessage name="password" />
    
    <button>Submit</button>
  </Form>
</template>
<script setup>
import { Form, Field, ErrorMessage } from 'vee-validate';
import * as yup from 'yup';
const schema = yup.object({
  email: yup.string().required().email(),
  password: yup.string().required().min(8),
});
</script>

Composition API

useFielduseFormが用意されていて、
setup内で完結できるよう。

フィールドのバリデーション
<template>
  <div>
    <input v-model="value" type="text" />
    <span>{{ errorMessage }}</span>
  </div>
</template>
<script setup>
import { defineProps, toRef } from 'vue';
import { useField } from 'vee-validate';
import * as yup from 'yup';

const props = defineProps({
  name: { type: String, required: true },
});

const nameRef = toRef(props, 'name');
const { errorMessage, value } = useField(nameRef, yup.string().required().min(8));
</script>

Field-level Validation with yup

フォームレベルでのバリデーション

<template>
  <div>
    <MyTextInput name="email" />
    <MyTextInput name="password" />
  </div>
</template>
<script setup>
import { useForm, useField } from 'vee-validate';
import * as yup from 'yup';
import MyTextInput from '@/components/MyTextInput.vue';

// Define a validation schema
const schema = yup.object({
  email: yup.string().required().email(),
  password: yup.string().required().min(8),
});
// Create a form context with the validation schema
useForm({
  validationSchema: schema,
});
</script>

Form-level Validation with yup

useFormで扱える値や関数

// in setup
import { useForm } from 'vee-validate';
interface LoginForm {
  email: string;
  password: string;
}

const { meta, isSubmitting, errors, handleSubmit, resetForm, setErrors, setFieldValue } = useForm<LoginForm>();

// validな状態
console.log(`valid=${meta.value.valid}`);

// submit中の状態
console.log(`isSubmitting=${isSubmitting.value}`);

// エラーの値
errors.value; // typed as { email?: string; password?: string }

// フォームの送信
const onSubmit = handleSubmit(values => {
  alert(JSON.stringify(values, null, 2));
});

// フォームのリセット
resetForm();

// エラーメッセージの設定
setErrors({
  email: 'This field is invalid', // auto-complete for `email` and `password`
});

// 値の設定
setFieldValue('email', 'example@gmail.com'); // auto-complete for the field name and its value type

いずれもFormコンポーネントでも受け取れる。

<Form as="" v-slot="{ meta, isSubmitting, errors, handleSubmit, resetForm, setErrors, setFieldValue }">
  <form @submit="submitForm">
    <!-- ... -->
  </form>
</Form>

Form

Yupを使うときの注意点

Best Practices

1.必要なものだけインポートする
// NG: 全部をimportする
import * as yup from 'yup';
// OK: 必要なものだけimportする
import { object, string } from 'yup';

const schema = yup.object({
  email: yup.string().email(),
  // ...
});
2.Yup schemaのリアクティブ

スキーマが固定である場合、無駄に変更を検知しないよう、
リアクティブにしないようにする。

{
  data() {
    // NG: リアクティブになっている
    const schema = yup.object({ /* ... */ });
    
    // OK-1: markRaw()で非リアクティブ化する
    const schema = markRaw(yup.object({ /* ... */ }));
    
    return { schema };
  },
  
  // OK-2: setup内でref()もreactive()も使ってない
  setup() {
    const schema = yup.object({ /* ... */ });
    
    return { schema };
  },
}

以上!! 結構変わってるけど、楽になった気がする(*´ω`*)

参考にしたサイト様