我是初学者。我正在尝试向快递服务器发出发布请求。我正在使用
typeScript
和 Shadcn/ui
表单以及 zod
验证。我必须发出像下面这个 JSON 对象一样的 POST 请求。我从服务器动态获取位置。 如何发送请求?
{
"description": "New Activity",
"price": 50,
"durationInMinutes": 120,
"placeId":1,
"locationId":1,
"status": "available"
}
这是我发出 POST 请求的表单代码,但这不起作用。验证如下
export const createActivityValidation = z.object({
description: z
.string({
required_error: "Description required",
invalid_type_error: "Description must be characters",
})
.min(1, "Description Needs More than 1 character"),
durationInMinutes: z.number(),
price: z.number(),
status: z
.string({
required_error: "Status required",
invalid_type_error: "Description must be characters",
})
.min(1, "Status is required"),
location: z.string({
required_error: "Place required",
invalid_type_error: "Please select the place",
}),
});
每次我提交表单时,zod 验证都会抛出错误,如 预期的数字,但得到字符串,而我的验证是数字。
const [loading, setLoading] = useState(false);
const [locations, setLocations] = useState<Location[]>([]);
const form = useForm<z.infer<typeof createActivityValidation>>({
resolver: zodResolver(createActivityValidation),
});
const onSubmit = async (value: z.infer<typeof createActivityValidation>) => {
console.log("value", value);
try {
setLoading(true);
const activityConfig = {
description: value.description,
durationInMinutes: value.durationInMinutes,
price: value.price,
status: value.status,
location: value.location,
};
const activityCreation = await fetcher.post(
"activities/activities",
activityConfig,
);
toast.success("Activity Created Successfully!");
console.log(activityCreation.data);
} catch (error) {
setLoading(false);
toast.error("Failed to create new Activity", {
description: "Something went wrong Please try later",
});
console.log(error);
}
};
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-2">
<FormField
control={form.control}
name="description"
render={({ field }) => (
<FormItem>
<FormLabel>Description</FormLabel>
<FormControl>
<Input
type="text"
placeholder="Activity Description"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="durationInMinutes"
render={({ field }) => (
<FormItem>
<FormLabel>Duration</FormLabel>
<FormControl>
<Input
type="number"
placeholder="Duration of activities in minutes"
onChange={(e) => {
const value = Number(e.target.value);
field.onChange(value);
}}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="price"
render={({ field }) => (
<FormItem>
<FormLabel>Price</FormLabel>
<FormControl>
<Input
type="number"
placeholder="Price"
onChange={(e) => {
const value = Number(e.target.value);
field.onChange(value);
}}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="status"
render={({ field }) => (
<FormItem>
<FormLabel>Status</FormLabel>
<FormControl>
<Input
type="text"
placeholder="available or unavailabe"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="status"
render={({ field }) => (
<FormItem>
<FormLabel>Status</FormLabel>
<FormControl>
<LocationSelector
value={field.value}
onChange={field.onChange}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button
variant="outline"
size="sm"
type="submit"
className="bg-primary text-secondary rounded-full gap-2"
disabled={loading}
>
{loading ? (
<span className="flex">
<CircleDashed size={20} className=" mr-1 animate-spin" />
Loading
</span>
) : (
<span className="flex">
<PlusIcon size={20} />
Create
</span>
)}
</Button>
);
}
这里的问题是,即使您在持续时间和价格的输入字段上设置 type="number",提交收到的数据时的表单中也是字符串。
您可以通过两种方式完成。
使用 z.number.or(z.string()) 代替 z.number() 并在 onSubmit 内部手动类型转换为
数据.价格 = 数字(数据.价格)
使用react-hook-form中的控制器在每个onChange事件上将输入字符串类型转换为数字。
从“react-hook-form”导入 { useForm, Controller, SubmitHandler };
const {
handleSubmit,
control,
register,
formState: { errors },
} = useForm<SchemaType>({
resolver: zodResolver(schema),
});
<Controller
control={control}
name="price"
render={({
field: { value, onChange },
}) => (
<input
value={value}
placeholder="Enter price"
type="number"
onChange={(e) => onChange(Number(e.target.value))}
/>
)}
/>