I have a zod schema that transforms a string (enum) value into an object. I want to use it with react-hook-forms
and the zodResolver
from @hookform/resolvers
. I'd like to use my transformed value with an Ant Design <Select>
.
Runnable code sandbox example: https://codesandbox.io/s/shy-water-cz9ryj?file=/src/App.js
The code currently looks like this:
import { useForm, Controller } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import * as z from "zod";
import { Select } from "antd";
const Foos = {
a: { key: "a", label: "A" },
b: { key: "b", label: "B" },
c: { key: "c", label: "C" }
};
const Schema = z.object({
foo: z.enum(["a", "b", "c"]).transform((key) => Foos[key])
});
const defaultValues = { foo: "a" };
export default function App() {
const {
handleSubmit,
control,
formState: { errors }
} = useForm({
defaultValues,
resolver: zodResolver(Schema)
});
return (
<div>
<form onSubmit={handleSubmit((d) => console.log(d))}>
<Controller
control={control}
name="foo"
render={({ field }) => (
<Select {...field} value={field.value.key}>
{Object.values(Foos).map((foo) => (
<Select.Option value={foo.key} key={foo.key}>
{foo.label}
</Select.Option>
))}
</Select>
)}
/>
</div>
);
}
This works in principle, but the initial value is not correctly displayed. The <Select>
appears emtpy until you select a value manually.
As shown in the codesandbox, this works as expected with native HTML <select>
and <option>
. That probably means that I am doing something wrong in regards to the Ant Design components.
Also, this works as expected with Ant Design and plain string values. It only broke when introducing the transformation to the schema.
Can someone give me a hint what I'm doing wrong here?
You need to use defaultValue
and field.defaultValue
instead of value
and field.value.key
:
export default function App() {
const {
handleSubmit,
control,
formState: { errors }
} = useForm({
defaultValues,
resolver: zodResolver(Schema)
});
return (
<div className="App">
<h2>Native HTML</h2>
<br />
<h2>Ant Design</h2>
<form onSubmit={handleSubmit((d) => console.log(d))}>
<Controller
control={control}
name="foo"
render={({ field }) => (
<Select {...field} defaultValue={field.defaultValue}>
{Object.values(Foos).map((foo) => (
<Select.Option value={foo.key} key={foo.key}>
{foo.label}
</Select.Option>
))}
</Select>
)}
/>
<br />
Error: {JSON.stringify(errors)}
<br />
<input type="submit" />
</form>
</div>
);
}
Here is the modified codeSandbox example: https://codesandbox.io/s/crazy-maria-mxhmno?file=/src/App.js