最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

reactjs - Zod refine not displaying errors for optional array fields in react-hook-form - Stack Overflow

programmeradmin2浏览0评论

I'm using Zod with react-hook-form to validate a form where at least one of two fields (warehouses or clusters) must be provided. Both fields are optional arrays of strings. I'm using .refine to enforce this logic, but the error message is not showing up for the fields.

Here's my Zod schema:

const schema = z.object({
    warehouses: z.array(z.string()).optional(),
    clusters: z.array(z.string()).optional(),
})
.refine((data) => (data.warehouses?.length ?? 0) > 0 || (data.clusters?.length ?? 0) > 0, {
    message: 'At least one warehouse or cluster must be provided',
    path: ['warehouses', 'clusters'],
});

I'm using a custom FormField component with Controller from react-hook-form, but the error message is not displayed for the fields. The problem is not in my custom FormField, but in zod schema and its error handlers

Here are my FormField components:

<FormField
    form={form}
    label={'Warehouses'}
    name="warehouses"
    render={({ field, fieldState }) => (
        <AutofillMultibox
            field={field}
            choices={['South', 'East', 'West'].map((e) => ({
                label: e,
                value: e,
            }))}
        />
    )}
/>
<FormField
    form={form}
    label={'Clusters'}
    name="clusters"
    render={({ field, fieldState }) => (
        <AutofillMultibox
            field={field}
            choices={['South', 'East', 'West'].map((e) => ({
                label: e,
                value: e,
            }))}
        />
    )}
/>

I'm using Zod with react-hook-form to validate a form where at least one of two fields (warehouses or clusters) must be provided. Both fields are optional arrays of strings. I'm using .refine to enforce this logic, but the error message is not showing up for the fields.

Here's my Zod schema:

const schema = z.object({
    warehouses: z.array(z.string()).optional(),
    clusters: z.array(z.string()).optional(),
})
.refine((data) => (data.warehouses?.length ?? 0) > 0 || (data.clusters?.length ?? 0) > 0, {
    message: 'At least one warehouse or cluster must be provided',
    path: ['warehouses', 'clusters'],
});

I'm using a custom FormField component with Controller from react-hook-form, but the error message is not displayed for the fields. The problem is not in my custom FormField, but in zod schema and its error handlers

Here are my FormField components:

<FormField
    form={form}
    label={'Warehouses'}
    name="warehouses"
    render={({ field, fieldState }) => (
        <AutofillMultibox
            field={field}
            choices={['South', 'East', 'West'].map((e) => ({
                label: e,
                value: e,
            }))}
        />
    )}
/>
<FormField
    form={form}
    label={'Clusters'}
    name="clusters"
    render={({ field, fieldState }) => (
        <AutofillMultibox
            field={field}
            choices={['South', 'East', 'West'].map((e) => ({
                label: e,
                value: e,
            }))}
        />
    )}
/>
Share Improve this question edited Mar 14 at 17:17 Nikita Dmitriev asked Mar 14 at 12:27 Nikita DmitrievNikita Dmitriev 511 silver badge6 bronze badges 2
  • 1 Aside: is it meant to be label={'Clusters'} name="warehouses"? – Caleth Commented Mar 14 at 12:59
  • @Caleth changed – Nikita Dmitriev Commented Mar 14 at 17:19
Add a comment  | 

2 Answers 2

Reset to default 1

Even though the path property in refine() accepts an array, it will only display the error if you set just one path.

To show multiple paths, you need to use .superRefine() instead of .refine(). See Display error messages in multiple locations using zod.

You can also chain .refine() calls, which I recommend in this situation. You can have two errors one for "At least one warehouse..." and one for "At least on cluster...".

Well, refine only works after all values have passed the default type checks. I expected an error earlier, just like the "Field is required" validation for other inputs. So I had to stop using refine and replace it with:

locations: z.discriminatedUnion('type', [
        z.object({
            type: z.literal('warehouses'),
            warehouses: z.array(z.string()).min(1, 'Choose at least 1 warehouse'),
            clusters: z.array(z.string()).default([]),
        }),
        z.object({
            type: z.literal('clusters'),
            clusters: z.array(z.string()).min(1, 'Choose at least 1 cluster'),
            warehouses: z.array(z.string()).default([]),
        }),
    ]),
发布评论

评论列表(0)

  1. 暂无评论