是的,当条件位于嵌套对象内时

dan*_*bgd 11 javascript reactjs yup react-hook-form

所以我在使用 yup 进行条件验证时遇到问题。基本上,我希望在未切换复选框时运输具有所需的属性。我正在使用 yup 的when功能,但我不知道如何引用sameShippingAsBillingshipping嵌套对象中的布尔值。

当复选框为 false 时,一切正常,显示错误...但是当选中复选框时,我收到此错误:"Cannot use 'in' operator to search for 'default' in undefined"

问题是is回调中的值未定义。是否可以从这些嵌套对象中访问外部变量when。有什么替代方法可以做到这一点?

这是沙箱示例

const schema = Yup.object({
  sameShippingAsBilling: Yup.bool(),
  billing: Yup.object({
    line1: Yup.string().required(),
    city: Yup.string().required(),
    country: Yup.string().required()
  }),
  shipping: Yup.object({
    line1: Yup.string().when("sameShippingAsBilling", {
      is: !val || val === false,
      then: Yup.string().required(),
    }),
    city: Yup.string().when("sameShippingAsBilling", {
      is: !val || val === false,
      then: Yup.string().required(),
    }),
    country: Yup.string().when("sameShippingAsBilling", {
      is: !val || val === false,
      then: Yup.string().required(),
    })
  })
});

const addrValues = { line1: "", city: "", country: "" };

const formOpts = {
  mode: "onChange",
  reValidateMode: "onChange",
  defaultValues: {
    sameShippingAsBilling: true,
    billing: { ...addrValues },
    shipping: { ...addrValues }
  },
  resolver: yupResolver(schema)
};

export default function CheckoutForm() {
  const methods = useForm(formOpts);
  const { watch } = methods;

  const shippingAsBilling = watch("sameShippingAsBilling");

  const onSubmit = async (data) => {
    console.log(data);
  };

  return (
    <MuiThemeProvider theme={createMuiTheme()}>
      <FormProvider {...methods}>
        <form onSubmit={methods.handleSubmit(onSubmit)} noValidate>
          <pre>errors: {JSON.stringify(methods.errors, null, 2)}</pre>

          <div className="group">
            <FormTextField name="billing.line1" />
            <FormTextField name="billing.city" />
            <FormTextField name="billing.country" />
          </div>

          <div>
            <FormCheckbox name="sameShippingAsBilling" />
          </div>

          {!shippingAsBilling && (
            <div className="group">
              <FormTextField name="shipping.line1" />
              <FormTextField name="shipping.city" />
              <FormTextField name="shipping.country" />
            </div>
          )}

          <div>
            <button type="submit">Pay</button>
          </div>
        </form>
      </FormProvider>
    </MuiThemeProvider>
  );
}
Run Code Online (Sandbox Code Playgroud)

jol*_*olo 18

shipping您可以根据该值有条件地渲染对象的形状sameShippingAsBilling

沿着这些思路:

    // define the boolean that stores if shipping details are the same as billing
    sameShippingAsBilling: Yup.bool(),
    shipping: Yup.object().when("sameShippingAsBilling", {
        // check if the boolean is false,   
        is: (sameShippingAsBilling) => sameShippingAsBilling === false,
        // if it is false, then use an object with required properties
        then: Yup.object().shape({
          line1: Yup.string().required(),
          city: Yup.string().required(),
          country: Yup.string().required(),
        }),
        // otherwise use an object without required properties
        otherwise: Yup.object().shape({
          line1: Yup.string(),
          city: Yup.string(),
          country: Yup.string(),
        }),
      }),
Run Code Online (Sandbox Code Playgroud)

  • 很好的解决方案。也适用于更深层次的嵌套。 (2认同)

dan*_*bgd 4

嗯,我添加了.nullable().default(null)运输,显然它有效。从技术上讲,仍然无法访问布尔真/假,它可以工作,因为 val 未定义,并且它添加了所需的条件...对于临时解决方案,它很好,我不必摆弄 .test() 或其他奇怪的解决方案。此时我什至不关心一个库将其称为“死简单的对象模式验证”,但我在这些简单的事情上浪费了时间。