까다로운 검증과정을 대신해주는 라이브러리
보통 form과 함께 사용한다.
따라서 리액트 훅 폼의‘Schema Validation’을 잘 보고 함께 사용할 것
- 설치명령어
yarn add yup
yarn add @hookform/resolvers yup
- index.tsx
import { useForm } from "react-hook-form"; import { wrapFormFunc } from "../../../src/commons/libraries/asyncFunc"; import { yupResolver } from "@hookform/resolvers/yup"; import { schema } from "./02-after.validation"; interface IFormData { writer: string; title: string; contents: string; boardAddress: { addressDetail: string; }; } export default function GraphqlMutationPage(): JSX.Element { //formState에서 에러메세지들을 받아오게 된다. const { register, handleSubmit, formState } = useForm<IFormData>({ resolver: yupResolver(schema), mode: "onChange", }); // 등록하기 함수 -> handleSubmit이 조종해주는 함수 const onClickSubmit = (data: IFormData): void => { console.log(data); // data.boardAddress.addressDetail }; return ( <form onSubmit={wrapFormFunc(handleSubmit(onClickSubmit))}> 작성자: <input type="text" {...register("writer")} /> { /* 생성한 yup의 에러메세지는 항상 errors에 담기는데 이 에러는 있을때도 있고 없을 때도 있기 때문에 옵셔널 체이닝을 붙여야 한다. */} <div style={{ color: "red" }}>{formState.errors.writer?.message}</div> 제목: <input type="text" {...register("title")} /> <div style={{ color: "red" }}>{formState.errors.title?.message}</div> 내용: <input type="text" {...register("contents")} /> <div style={{ color: "red" }}>{formState.errors.contents?.message}</div> {/* 주소: <input type="text" {...register("boardAddress.addressDetail")} /> */} <button style={{ background: formState.isValid ? "yellow" : "" }}> Graphql-API 요청하기 </button> </form> ); }
resolver에는 yup이외에도 다른 검증 라이브러리를 사용할 수 있다❗️
- validation.ts
import * as yup from "yup"; // yup 에러메세지 생성해주기 -> 제어 컴포넌트 형태로 사용해야한다. export const schema = yup.object({ writer: yup.string().required("필수입력"), // writer: yup.string().min(2,"최소 2자 이상입니다").required("작성자는 필수입력입니다") title: yup.string().required("필수입력"), contents: yup.string().required("필수입력"), // email: yup.string().email("형식 부적합").required("필수입력"), // password: yup // .string() // .min(8, "최소 8자리 이상") // .max(15, "최대 15자리 이상") // .required("필수입력"), // phone: yup // .string() // .matches(/^\d{3}-\d{3,4}-\d{4}$/, "형식 부적합") // .required("필수입력"), });
button과 input이 공통적으로 사용되고 있음으로
컴포넌트 따로 빼주기!
- index.tsx
import Input01 from "../../../src/components/commons/inputs/01"; import Button01 from "../../../src/components/commons/buttons/01"; export default function GraphqlMutationPage(): JSX.Element { const { register, handleSubmit, formState } = useForm<IFormData>({ resolver: yupResolver(schema), mode: "onChange", }); return ( <form onSubmit={wrapFormFunc(handleSubmit(onClickSubmit))}> 작성자: <Input01 register={register("writer")} /> <div style={{ color: "red" }}>{formState.errors.writer?.message}</div> 제목: <Input01 register={register("title")} /> <div style={{ color: "red" }}>{formState.errors.title?.message}</div> 내용: <Input01 register={register("contents")} /> <div style={{ color: "red" }}>{formState.errors.contents?.message}</div> <Button01 title="등록하기" isActive={formState.isValid} /> </form> ); }
- src/components/commons/inputs
import type { UseFormRegisterReturn } from "react-hook-form"; interface IInputProps { type?: "text" | "password"; register: UseFormRegisterReturn; } export default function Input01(props: IInputProps) { return <input type={props.type ?? "text"} {...props.register} />; }
- src/components/commons/buttons
interface IButtonProps { isActive: boolean; title: string; } export default function Button01(props: IButtonProps): JSX.Element { return ( <button style={{ background: props.isActive ? "yellow" : "" }}> {props.title} </button> ); }
스토리북
공통컴포넌트를 따로 모아놓고 쉽게 볼 수있게 해주는 라이브러리
- 설치명령어
yarn add @storybook/react
https://storybook.js.org/docs/react/get-started/install/
아니 이렇게 간단한 방법이 있었따니이이이이잉