Zodで基本的なバリデーションをかけてみる
バリデーションライブラリ「Zod」の基本的な使い方についてまとめてみる。
Zodは、スキーマファーストなバリデーションライブラリ。 はじめにスキーマを定義して、パースすることでバリデーションをかけることができる。
スキーマを定義する
varidation.ts
import { z } from "zod";
export type ValidationErrors = { [k: string]: string[] };
// schemaの定義
export const schema = z.object({
text: z
.string()
.nonempty({ message: "入力は必須です。" })
.min(5, "5文字以上で入力してください。")
});
export type TextInput = z.infer<typeof schema>;
// バリデーションに成功したら、データを返す
// 失敗すれば、エラーメッセージを返す
export const textValidate = (
targetData: TextInput,
success?: (result: TextInput) => void,
fail?: (errors: ValidationErrors) => void
): void => {
const result = schema.safeParse(targetData);
if (result.success) {
if (success) success(result.data);
} else if (fail) fail(result.error.flatten().fieldErrors);
};
nonempty
は入力必須 min
は最小文字数を定義できる 続けて、表示したいエラーメッセージを記述することができる。 上記のバリデーションを実行して、エラーメッセージを格納するロジックをカスタムフックに分離させる。
エラーメッセージを取得して格納する
hooks.ts
import { useCallback, useState } from "react";
import { textValidate, TextInput, ValidationErrors } from "./varidation";
export const useValidation = (): {
validateErrors: ValidationErrors;
doValidate: (textInput: TextInput, cb?: (result: TextInput) => void) => void;
} => {
// エラーメッセージの格納
const [validateErrors, setValidateErrors] = useState<ValidationErrors>({
text: []
});
const doValidate = useCallback(
(textInput: TextInput, cb?: (result: TextInput) => void) => {
textValidate(
textInput,
(result: TextInput) => {
setValidateErrors({
text: []
});
if (cb) cb(result);
},
(errors) => {
setValidateErrors({
...errors
});
}
);
},
[]
);
return { validateErrors, doValidate };
};
エラーメッセージは、複数のフォームに対応するため、オブジェクトで持たせる
{
email: []
password: []
}
コンポーネントで使用
App.tsx
import React, { useState, useCallback } from "react";
import styled from "styled-components";
import { useValidation } from "./hooks";
import { TextInput } from "./varidation";
import TextInputField from "./TextInput";
import InputError from "./InputError";
import "./styles.css";
export type Props = {
className?: string;
};
export const App: React.VFC<Props> = ({ className }) => {
const [Input, setInput] = useState({ text: "" });
const { validateErrors, doValidate } = useValidation();
const changeInput = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
setInput({
text: e.target.value
});
},
[setInput]
);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
doValidate(Input, (result: TextInput) => console.log(result));
};
return (
<div className={className}>
<form onSubmit={handleSubmit}>
<div className={`formInput`}>
<InputError errorMessages={validateErrors.text}>
<TextInputField
name="text"
placeholder="Text"
onChange={changeInput}
value={Input.text}
isError={validateErrors.text.length > 0}
/>
</InputError>
</div>
<button type="submit">Submit</button>
</form>
</div>
);
};
export const StyledComponent = styled(App)`
padding: 16px;
form {
margin: 0 auto;
}
`;
export default StyledComponent;
設定したバリデーションエラーを格納して、エラーメッセージを表示することができた。 <InputError>
コンポーネントは、単純にエラーメッセージを受け取って、表示するだけのコンポーネント。