reactjs 使用ZOD和React验证日期|开始日期〈结束日期

pgky5nke  于 2023-04-05  发布在  React
关注(0)|答案(1)|浏览(276)

我正在创建一个表单,用户可以在其中向他的假期应用程序添加假期。我使用zod作为验证。规则是-开始日期不能在过去,结束日期不能与开始日期相同或在开始日期之前。我试图向endDate添加一个细化方法,但我无法访问startDate的值。有什么想法可以让这种验证发生吗?

注意在我的Vacation.ts中有一个基本验证-

this.startDate =
  startDate < new Date()
    ? (() => {
        throw new Error("Start date cannot be earlier than today.");
      })()
    : startDate;
this.endDate =
  endDate < startDate
    ? (() => {
        throw new Error("End date cannot be earlier than start date.");
      })()
    : endDate;

但我希望在提交之前在表单本身进行额外的验证,使用onBlur,这样它就可以在用户选择日期时动态更改。
我也在考虑使用MUI的范围日期选择器。不确定这是否能解决任何问题。
这是我的代码:

function AddVacation(): JSX.Element {
let allVacations: Vacation[] = [];
type FormData = {
    // id: number,
    destination: string,
    startDate: Date,
    endDate: Date,
    vacDesc: string,
    vacPrice: number,
    vacImg: string,
  }
  // This will be the schema for the form, it'll be used to validate the form when submitting.
  //z.coerce.date() is used to convert the string to a date object.
  const schema: ZodType<FormData> = z.object({
    destination: z.string().min(2, {message: 'Destination must have at least 2 characters'}).nonempty(),
    startDate: z.coerce.date().refine((data) => data > new Date(), {message: 'Start date must be in the future'}),
    endDate: z.coerce.date(),
    vacDesc: z.string().min(2).nonempty(),
    vacPrice: z.number().positive().max(1000),
    vacImg: z.string().nonempty()
  })
  const navigate = useNavigate();
  const { register, handleSubmit, trigger ,formState: { errors } } = useForm<FormData>({resolver: zodResolver(schema)});
  const onSubmit = (data: FormData) => {
        console.log("submitting...")
        console.log(errors);
        const newVacation = new Vacation(data.destination, data.startDate, data.endDate, data.vacDesc, data.vacPrice, data.vacImg);
        allVacations.push(newVacation);
        console.log(data);
        console.log(`allVacations: ${allVacations}`)
        navigate("/vacationList")
  }
toe95027

toe950271#

您可以将.refine添加到模式本身,并在path中传递endDate,以指定endDate是导致错误的原因,而不仅仅是表单本身的一般错误。
(为了简单起见,我在这个例子中删除了额外的字段,并将年份设置为2100,以使这个例子在一段时间内有效)

import { z, ZodType } from "zod";

type FormData = {
  startDate: Date;
  endDate: Date;
};
// This will be the schema for the form, it'll be used to validate the form when submitting.
//z.coerce.date() is used to convert the string to a date object.
const schema: ZodType<FormData> = z
  .object({
    startDate: z.coerce.date().refine((data) => data > new Date(), { message: "Start date must be in the future" }),
    endDate: z.coerce.date(),
  })
  .refine((data) => data.endDate > data.startDate, {
    message: "End date cannot be earlier than start date.",
    path: ["endDate"],
  });

通过这些测试,代码可以正常工作

const shouldPass = schema.safeParse({
  startDate: "2100-01-01",
  endDate: "2100-01-02",
});
console.log(shouldPass.success); // true
if (shouldPass.success) {
  console.log(shouldPass.data); 
  /*
  {
    "startDate": 2100-01-01T00:00:00.000Z,
    "endDate": 2100-01-02T00:00:00.000Z
  }
  */
} else {
  console.log(shouldPass.error); // doesn't get here
}

const shouldFail = schema.safeParse({
  startDate: "2100-01-02",
  endDate: "2100-01-01",
});
console.log(shouldFail.success); // false
if (shouldFail.success) {
  console.log(shouldFail.data); // doesn't get here
} else {
  console.log(shouldFail.error);
  /*
  {
    "code": "custom",
    "message": "End date cannot be earlier than start date.",
    "path": [
      "endDate"
    ]
  }
  */
}

相关问题