react-hook-form字段数组自定义精炼错误状态不会更新

问题描述 投票:0回答:1

我的

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

如何测试?

  1. 单击
    add url
    按钮。

enter image description here

  1. 点击切换按钮,此时控制台打印
    refine true
    ,表示验证通过,但
    error?.message
    未更新。

enter image description here

reactjs react-hook-form zod
1个回答
1
投票

您可以使用

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 是故意这样做的,以避免不必要的重新渲染。

© www.soinside.com 2019 - 2024. All rights reserved.