📑

【MUI×Zod×RHF】複数のチェックボックス群にバリデーションさせたい

に公開

はじめに

実際の業務で初めてMUIで構成されたReactHookFormをZodで管理することになり、
つまづいたので備忘録として残しておく

前提知識

MUI

https://mui.com/

  • コンポーネントライブラリの1つ。スタイルつきで簡単に統一したレイアウトが作成できる。
  • MUIのコンポーネントにはContorolledComponentUnContorolledComponentという概念がある。
  • ContorolledComponentとはstateなどの状態によって変化させるコンポーネントのことであり、入力フォームなどは基本的にContorolledComponentになる。
Zod

https://zod.dev/

  • TS向けのバリデーションスキーマライブラリ
  • 型定義と実行時チェックを一括で行えるのが強み
RHF(React Hook Form)

https://react-hook-form.com/

  • React向けのフォーム管理ライブラリ
  • 最小限のレンダリング、ZodやYupなどのバリデーションとの連携が簡単

やりたいこと

以下のParents.tsxChildrenというコンポーネントを配置し、
Childrenというコンポーネントに複数のチェックボックスを作成。
Children内の複数チェックボックス全体に対して、バリデーションを実装したい。

Parents.tsx

import { z } from "zod";
import { FormProvider, useForm } from "react-hook-form";
import { Box } from "@mui/material";
import Children from "~hogehoge";

const Schema = z.object({
 checkBox : z.array(z.number()).superRefine((a,index)=>{
  //やりたいバリデーションルール
  message : "エラーメッセージ",
 }),

export type ValidationShemaType = z.infer<typeof Schema>;

const Parents = () {
 const methods = useForm<ValidationShemaType>({
  mode : "onChange",
  resolver : zodResolver(ValidationShemaType),
  defaultValues :{
   checkBox : [],
  }
 });

return (
 <FormProvider {...methods}>
  <Box component={"form"} submitAction={onSubmit}>
   <Children user={userData} />
  </Box>
 </FormProvider>
);

export default Parents;


実際のコード

Children.tsx
import { ValidationShemaType } from "../Parents";
import { Controller, useFormContext } from "react-hook-form";
import { FormGroup, FormContorolLabel, Checkbox } from "@mui/material";

type Props =hogehoge;

const Children = ({user}:Props) {
 const { contorol, formState: { erros } , } = useFormContext<ValidationShemaType>;
};

return (
 <FormGroup>
  <Controller
    name="checkBox"
    control={contorol}
    render={({field}) =>{
      <>
      //レンダーさせたいチェックボックス群.map((hoge) => (
       <FormContorolLabel
        key={hoge.id}
        contorol={
         <CheckBox>
       />
      ))}    
    {erros.checkBox && (
        <div style={{color:"red"}}>
        {erros.checkBox.message}
        </div>
       )}
      </>
     )}
   />
 </FormGroup>
);

export default Children;

まとめ

  • RHFで、MUIなどの外部のUIコンポーネントライブラリを管理したいとき、Contorollerを使う
  • RHF内のフォームのname属性と、Zodで定義したスキーマの属性名は揃える
  • RHFのFormProviderは囲まれているコンポーネント内でRHFのメソッド、プロパティにアクセスできる
    • FormProvider利用側はuseFormContextを介して利用する

課題

今回はRHFのContorollerとMUIを組み合わせたが、Contorollerなしでも実装できるようなので調べてみたい

Discussion