IT/언어

[Vue3] Vue3 베이스의 밸리데이션 프레임워크 VeeValidate(v4)

개발자 두더지 2023. 8. 17. 22:47
728x90

일본의 한 블로그 글을 번역한 포스트입니다. 오역 및 의역, 직역이 존재할 수 있으며, 틀린 내용은 지적해주시면 감사하겠습니다.

 

 Vue에서 대표적인 밸리데이션 워크 프레임으로 말하자면 VeeValidate가 있다. VeeValidate는 기능이 많고 사용하기 쉬운 프레임워크이지만, Vue2계에 대응하는 v3와 Vue3계에 대응하는 v4는 완전 다른 것이라고 이야기될 정도로 사용방법이 많이 바꼈다.

 이번에는 이러한 VeeValidate v4의 사용 방법에 대해서 정리하고자한다.

 

 

VeeValidate의 사용 스타일


 VeeValidate(v4)의 사용을 하기 위해는 아래의 두 개의 구현 스타일이 존재한다.

  • Composition API
  • Higher-order components(HOC)

 첫 번째의 Composition API는 VeeValidate가 제공하는 Composable을 사용하는 방법이다. 특정 UI가 없기 때문에 기존의 컴포넌트에 도입하는 등의 유연한 사용이 가능하다.

 두 번째의 Higher-order componenets는 VeeValidate가 제공하는 Vue 컴포넌트(Form/Field등)을 사용하는 방법이다. Composition API를 직접 사용하는 것 보다는 심플하게 구현이 가능하다. 

 두 가지는 배타적인 것이 아니므로 적재적소에 사용방법을 적용할 수 있다. 아래에서 각각의 사용법에 대해서 간략하게 살펴보자

 

 

Higher-order components (HOC)


 먼저 간단한 쪽부터 설명하도록 하겠다. 앞서 언급했는 Higher-order componets는 VeeValidate가 제공하는 Vue 컴포넌트를 사용하는 방법이다. 

 

필드 레벨의 밸리데이션

 거의 공식 문서 그대로이지만, 최소한의 구현 방법은 다음과 같다.

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

  const isRequired = (value) => value && value.trim() ? true : '이름은 필수항목입니다!';
</script>

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

 VeeValidate가 제공하는 폼(Form)을 배치하여 자식 요소로서 입력 필드(Field)나 에러 메시지(ErrorMessgae)를 둔다. 각 컴포넌트의 역할은 이름 그대로이다.

 중요한 밸리데이션 로직은 Field의 rules Props로 지정한다. 함수 자체는 OK인 경우 true, NG인 경우 에러 메시지를 반환한다. 

 이 코드를 실행하면 밸리데이션 에러가 발생시에 다음과 같이 HTML가 랜더링된다. 

<form novalidate>
  <input name="name">
  <span role="alert">이름은 필수항목입니다!</span>
</form>

 물론 이것은 어디까지나 기본 설정의 경우이다. 컴포넌트의 Props나 Slot을 지정하여 UI를 커스터마이즈할 수 있다. 상세한 내용에 대해서는 공식 문서들을 참고하길 바란다.

 또한 밸리데이션 로직은 글로벌 정의도 가능하다. 이용 빈도가 높은 것은 이 방법을 이용하는 것을 추천하다. 

 

Form 레벨의 밸리데이션

 방금건 각각의 필드에 대한 밸리데이션을 지정했지만, 폼 단위로 정리하여 룰을 지정하는 방법도 서포트되고 있다. 이 경우는 아래와 같이 구현할 수 있다.

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

  const schema = {
    lastName(value) {
      return value && value.trim() ? true : '성은 필수항목입니다!';
    },
    firstName(value) {
      return value && value.trim() ? true : '이름은 필수항목입니다!';
    }
  };
</script>

<template>
  <Form :validationSchema="schema">
    <Field name="lastName" />
    <ErrorMessage name="lastName" />
    <Field name="firstName" />
    <ErrorMessage name="firstName" />
  </Form>
</template>

 앞서 본 것과 같이 각각의 Field 컴포넌트의 rules를 지정하는 것이 아닌, Form 컴포넌트의 validationSchema에 각 필드의 룰을 정리한 오브젝트를 지정한다.

 일반적으로는 필드 레벨이아닌 이 방법을 사용하는 경우가 많다.

 

밸리데이션 라이브러리를 사용하기

 지금까지는 밸리데이션 로직을 자체 제작했지만, VeeValidate v4에서는 기존의 밸리데이션 라이브러리가 포함되어 있다. 현재로서는 Yup, Zod, Valibot이 서포트되고 있다.

 공식 문제에는 주로 Yup을 사용한 방법이 기재되어 있지만, 여기서는 인기 급상승 중인 Zod로 실험해봤다. 방금 봤던 코드를 Zod로 구현하면 다음과 같다.

<script setup lang="ts">
import { ErrorMessage, Field, Form } from 'vee-validate';
import { z } from 'zod';
import { toTypedSchema } from '@vee-validate/zod';

const schema = toTypedSchema(
  z.object({
    lastName: z.string({ required_error: '성은 필수항목입니다!' }),
    firstName: z.string({ required_error: '이름은 필수항목입니다!' })
  })
);
</script>

<template>
  <Form :validationSchema="schema">
    <Field name="lastName" />
    <ErrorMessage name="lastName" />
    <Field name="firstName" />
    <ErrorMessage name="firstName" />
  </Form>
</template>

 @vee-validate/zod의 toTypedSchema로 Zod의 스키마를 VeeValidate가 번역할 수 있는 형태로 변환하고 있다. Yup도 Zod등의 라이브러리는 풍부하게 스키마 정의가 되어있으므로, 자체 제작하는 것보다는 이러한 라이브러리를 사용하는 것이 간단하다.

 

폼 서브밋

 VeeValidate v3에서는 v-model로 지정했던 값에 대해서 밸리데이션했다. VeeValidate v4에서는 v-model를 사용하여 동일하게 할 수 있으나, 필수로 기재해야할 필요성이 없어졌다. 즉, 필드의 값은 VeeValidate로 관리한다. 

이것은 VeeValidate가 폼 서브밋하지 않은 값을 어플리케이션에서 다룰 필요성이 적어졌다는 생각으로 인한 것 같다.  v3에서는 폼 서브밋은 이용자의 구현에 맡겼지만, v4에서는 이러한 것을 네이티브 서포트하고 있다. 

 폼 서브밋은 JavaScript를 단순히 실행하는 스타일도, HTML 디폴트의 페이지 리로드를 동반하여 데이터를 송신하는 스타일으로도 가능하다. 

 양쪽 케이스에서의 VeeValidate는 밸리데이션이 패스하지 않으면 폼 서브밋을 발동하지 않도록 해준다(기본설정으로).

 아래는 폼 서브밋의 실행예이다.

<script setup lang="ts">
import { ErrorMessage, Field, Form } from 'vee-validate';
import { z } from 'zod';
import { toTypedSchema } from '@vee-validate/zod';

const schema = toTypedSchema(
  z.object({
    lastName: z.string({ required_error: '성은 필수항목입니다!' }),
    firstName: z.string({ required_error: '이름은 필수항목입니다!' })
  })
);
const submit = (values) => {
  console.log(values)
  // { lastName: 'xxxx', firstName: 'yyyy' }
  // ...서브밋 처리
}
</script>

<template>
  <!-- HTML폼 서브밋의 경우 -->
  <!-- <Form :validationSchema="schema" action="/api/user" method="post"> -->
  <Form :validationSchema="schema" @submit="submit">
    <Field name="lastName" />
    <ErrorMessage name="lastName" />
    <Field name="firstName" />
    <ErrorMessage name="firstName" />
    <button>송신</button>
  </Form>
</template>

 이 코드에서는 밸리데이션이 모두 통과한 상태에서 송신 버튼이 클릭되면 submit 함수가 실행된다. 이때의 인수로서 필드의 값이 전달된다. 함수 내에서는 그러한 값들이 적절한 값이라는 것이 보증된 상태에서 뒤에 여러 처리를 실행할 수 있게 된다.

 

 

Composition API


 다음은 다른 스타일인 Composition API에 대한 설명이다. 이쪽의 경우 VeeValidate가 제공하는 Vue 컴포넌트가 아닌 Compsable을 사용하여 구현한다.

 방금의 경우는 HTML 랜더링도 있었지만, 이 스타일은 UI에는 일절 관여하지 않기 때문에 보다 자유도 높은 구현이 가능하다. 

 그렇다고하더라도 밸리데이션의 구현 방법이나 폼 서브밋의 원리는 Vue 컴포넌트와 거의 동일하다. 마지막의 예를 Composition API로 구현하자면 다음과 같이 구현하게 된다.

<script setup lang="ts">
  import { useForm } from 'vee-validate';
  import { z } from 'zod';
  import { toTypedSchema } from '@vee-validate/zod';

  const { defineInputBinds, errors, handleSubmit } = useForm({
    validationSchema: toTypedSchema(
      z.object({
        lastName: z.string({ required_error: '성은 필수항목입니다!' }),
        firstName: z.string({ required_error: '이름은 필수항목입니다!' })
      })
    )
  });

  const submit = handleSubmit((values) => {
    console.log(values);
    // { lastName: 'xxxx', firstName: 'yyyy' }
  })

  const lastName = defineInputBinds('lastName');
  const firstName = defineInputBinds('firstName');
</script>

<template>
  <form @submit="submit">
    <input v-bind="lastName" />
    <span>{{ errors.lastName }}</span>
    <input v-bind="firstName" />
    <span>{{ errors.firstName }}</span>
    <button>Submit</button>
  </form>
</template>

 포인트는 useForm Composable이다. 이것은 폼 레벨 밸리데이션의 기본 기능을 제공하는 것이다. 여기서 Zod의 스키마 정의를 지정(validationSchema)하고 있다.

 Zod의 스키마 정의 자체는 방금의 Vue 컴포넌트로 지정한 것과 완전히 동일하다. 그 후에는 useForm가 반한괎으로서 제공하는 각종 함수나 데이터를 구사하여 밸리데이션과 관련된 UI를 구성한다.

  • defineInputBinds: 폼에 HTML 입력 요소(v-bind)를 연관시킨다.대상이 Vue 컴포넌트 자체인 경우 define Component Binds 함수를 사용한다.
  • errors : 에러 내용을 저장하는 리얼 데이터. 에러 유무의 판정이나 UI에 에러 메세지를 표시한다.
  • handleSubmit: 폼 서브밋의 도우미 함수. 이벤트 전파 억제 및 실행 타이밍을 제어한다.

이외에도 useForm Composable은 다수의 기능을 제공하고 있다. 또한 여기서는 사용하지 않았지만 필드 레벨의 밸리데이션의 제공하는 useFiled Composable도 존재한다. 그 외 상세한 내용은 공식문서를 참조하길 바란다.


참고자료

https://developer.mamezou-tech.com/blogs/2023/08/16/vee-validate-v4-intro/

728x90

'IT > 언어' 카테고리의 다른 글

[React] 커스텀 훅  (0) 2023.09.10
[SCSS] SCSS의 mixin 기초  (0) 2023.08.20
[Vue3] Suspense 기능의 간략한 사용법  (0) 2023.08.15
[Java] 정규표현  (0) 2023.07.26
[JavaScript] Blob의 사용법  (0) 2023.07.21