我的
fieldValues
如下:
export const schema = z.object({
urls: z
.array(
z.object({
path: z.string().url(),
main: z.boolean(),
id: z.string(),
})
)
.min(1)
.max(3)
.refine(
(urls) => {
const result = urls.some((url) => url.main);
console.log("refine", result);
return result;
},
{
message: "at least there is a main site!",
}
),
});
有一个自定义验证逻辑,该逻辑是
urls
必须有一个url
标记为主站点。
但是我发现内置的
min()
和 max()
工作得很好,虽然我的自定义验证规则被触发了,但是 error.message
并没有更新。
表格.tsx
import { Controller, useFieldArray, useFormContext } from "react-hook-form";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import RemoveCircleTwoToneIcon from "@mui/icons-material/RemoveCircleTwoTone";
import { Button } from "@mui/material";
import RHFTextField from "./RHFTextField";
import RHFSwitch from "./RHFSwitch";
const Form = () => {
const { control } = useFormContext<Schema>();
const { append, fields, remove } = useFieldArray({
control,
name: "urls",
});
return (
<Controller
name="urls"
control={control}
render={({ field, fieldState: { error } }) => {
return (
<Stack spacing={1}>
<Stack direction={"row"} alignItems={"center"} spacing={1}>
<Typography variant={"h6"}>urls</Typography>
<Typography variant={"body2"} color={"error"}>
{error?.message}
</Typography>
</Stack>
{fields.map((url, index) => (
<Stack key={url.id} direction={"row"}>
<div className="pr-1 h-[38px] flex items-center">
<RemoveCircleTwoToneIcon
color={"error"}
onClick={() => {
remove(index);
}}
/>
</div>
<RHFTextField name={`urls.${index}.path`} className="flex-1" />
<RHFSwitch name={`urls.${index}.main`} />
</Stack>
))}
<Button
variant="text"
onClick={() => {
append({
path: "",
main: false,
id: window.crypto.randomUUID(),
});
}}
>
add url
</Button>
</Stack>
);
}}
/>
);
};
export default Form;
https://codesandbox.io/p/sandbox/react-hook-form-1-wwqnkk?file=%2Fsrc%2Fschema.ts
add url
按钮。refine true
,表示验证通过,但error?.message
未更新。您可以使用
trigger
方法来触发 "urls"
对 RHFSwitch
组件更改的路径验证:
const RHFSwitch = memo(({ label, name, ...props }: Props) => {
const { control, trigger } = useFormContext();
return (
<Controller
name={name}
control={control}
render={({
field: { value, onChange, ...field },
fieldState: { error },
}) => (
<Stack direction={"row"} justifyContent={"space-between"}>
<Typography variant="h6">{label}</Typography>
<Switch
checked={value}
onChange={(e) => {
onChange(e);
trigger("urls");
}}
{...field}
{...props}
/>
</Stack>
)}
/>
);
});
解释
zod 的
refine
方法处理的错误会注册在 "urls"
对象的 errors
路径中,您可以在 formState
中找到该路径。
仅当您向字段数组添加/删除项目时才会触发
"urls"
路径验证。
我不确定,但我猜 RHF 是故意这样做的,以避免不必要的重新渲染。