😽
react-fook-formとmuiを連携して型安全に使う
はじめに
react-fook-formとmuiを連携したTextField
作成時に型安全に扱いたい場合の忘備録
型補完の効かないコード
前提として、muiからimportしたTextFieldはコンポーネントとして切り出します。
それぞれ使いた場所で呼び出す形にします。
InputTextField
import { TextField, TextFieldProps } from "@mui/material";
import { Controller, useFormContext } from "react-hook-form";
type Props = {
name: string;
} & TextFieldProps;
export const InputTextField = ({ name, ...rest }: Props) => {
const { control } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({ field }) => <TextField {...field} {...rest} />}
)}
/>
);
};
このままだと呼び出し先では、nameに渡す値は文字列なので補完が効きません
index
import { InputTextField } from "@/components/InputTextField";
import { Button } from "@mui/material";
import { SubmitHandler, useFormContext } from "react-hook-form";
export type FormValues = {
text: string;
};
type Props = {
onSubmit: SubmitHandler<FormValues>;
};
export const PopupForm = ({ onSubmit }: Props) => {
const { handleSubmit } = useForm<FormValues>();
return (
<form onSubmit={handleSubmit(onSubmit)}>
<InputTextField
name=""
/>
<Button type="submit" color="primary" variant="contained">
確定
</Button>
</form>
);
};
型補完が効くコード
InputTextFieldコンポーネントをこのように型定義してあげましょう
TextField
type Props<T extends FieldValues> = {
name: Path<T>;
control: Control<T>;
} & TextFieldProps;
export const TextField = <T extends FieldValues>({
name,
control,
...rest
}: Props<T>) => {
return (
<Controller
name={name}
control={control}
render={({ field }) => <MuiTextField {...field} {...rest} />}
/>
);
};
これで呼び出し先で型補完が効くので開発効率アップですね
FormValuesで定義していない値をnameで渡そうとすると怒られます
index
import { InputTextField } from "@/components/InputTextField";
import { Button } from "@mui/material";
import { SubmitHandler, useFormContext } from "react-hook-form";
export type FormValues = {
text: string;
};
type Props = {
onSubmit: SubmitHandler<FormValues>;
};
export const PopupForm = ({ onSubmit }: Props) => {
const { control, handleSubmit } = useForm<FormValues>();
return (
<form onSubmit={handleSubmit(onSubmit)}>
<InputTextField
name="text"
control={control}
/>
<Button type="submit" color="primary" variant="contained">
確定
</Button>
</form>
);
};
Discussion