Мои 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.info("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
не обновлена.🤔 А знаете ли вы, что...
React Testing Library - это инструмент для тестирования компонентов React.
Вы можете использовать метод 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>
)}
/>
);
});
Объяснение
Ошибки, обрабатываемые методом refine
Зода, регистрируются в пути "urls"
объекта errors
, который вы можете найти внутри formState
.
Проверка пути "urls"
запускается только тогда, когда вы добавляете/удаляете элемент в массив полей.
Я не уверен, но думаю, что RHF делает это намеренно, чтобы избежать ненужного повторного рендеринга материала.