You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ReactJS中基于Formik+Yup实现按选中国家正则验证邮编的方案咨询

Hey there! 我之前刚好做过类似的Formik+Yup动态验证需求,给你梳理一套清晰的实现思路,分几步来就搞定了:

实现步骤拆解

1. 先准备好国家与邮编规则的数据源

首先得把各个国家对应的邮编验证正则整理成结构化的数组,方便后续匹配:

// 示例数据,你可以根据需求扩展更多国家
const countryPostalRules = [
  {
    name: "中国",
    value: "CN",
    postalRegex: /^[1-9]\d{5}$/
  },
  {
    name: "美国",
    value: "US",
    postalRegex: /^\d{5}(-\d{4})?$/
  },
  {
    name: "英国",
    value: "GB",
    postalRegex: /^[A-Z]{1,2}\d[A-Z\d]? \d[A-Z]{2}$/i
  }
];

2. 初始化Formik表单状态

在Formik的初始值里定义好country和postalCode两个字段,默认值可以根据需求设置:

const initialValues = {
  country: "", // 初始为空,也可以设成默认选中的国家值,比如"CN"
  postalCode: ""
};

3. 核心:用Yup的when方法实现动态验证

这一步是关键!Yup的when方法允许我们根据其他字段的取值,动态切换当前字段的验证规则。结合test方法,我们可以自定义邮编的验证逻辑:

import * as Yup from 'yup';

const validationSchema = Yup.object().shape({
  country: Yup.string().required("请选择国家"),
  postalCode: Yup.string()
    .required("请输入邮编")
    // 当country字段有值时,触发动态验证
    .when("country", {
      is: (selectedCountry) => !!selectedCountry,
      then: (schema) => schema.test(
        "postal-code-validation", // 自定义测试名称
        "请输入符合当前国家格式的邮编", // 错误提示语
        function(value) {
          // 通过this.parent获取整个表单的字段值,找到当前选中的国家规则
          const matchedRule = countryPostalRules.find(
            rule => rule.value === this.parent.country
          );
          // 如果没匹配到规则,默认通过(也可以根据需求改成不通过)
          if (!matchedRule) return true;
          // 用对应正则验证邮编
          return matchedRule.postalRegex.test(value);
        }
      )
    })
});

⚠️ 注意:这里的test方法要用普通函数,不能用箭头函数,因为需要通过this访问表单的上下文(this.parent就是整个表单的values对象)。

4. 渲染表单组件

用Formik的Field组件渲染下拉框和输入框,下拉框的选项直接从我们准备的countryPostalRules数组生成:

import { Formik, Form, Field } from 'formik';

// 组件内部渲染
<Formik
  initialValues={initialValues}
  validationSchema={validationSchema}
  onSubmit={(values) => {
    // 处理表单提交逻辑
    console.log("提交的表单数据:", values);
  }}
>
  {({ errors, touched }) => (
    <Form>
      {/* 国家选择下拉框 */}
      <div className="form-group">
        <label>选择国家</label>
        <Field as="select" name="country">
          <option value="">请选择国家</option>
          {countryPostalRules.map(rule => (
            <option key={rule.value} value={rule.value}>
              {rule.name}
            </option>
          ))}
        </Field>
        {/* 错误提示 */}
        {errors.country && touched.country && (
          <span className="error-text">{errors.country}</span>
        )}
      </div>

      {/* 邮编输入框 */}
      <div className="form-group">
        <label>邮编</label>
        <Field type="text" name="postalCode" placeholder="请输入邮编" />
        {/* 错误提示 */}
        {errors.postalCode && touched.postalCode && (
          <span className="error-text">{errors.postalCode}</span>
        )}
      </div>

      <button type="submit">提交表单</button>
    </Form>
  )}
</Formik>

额外优化小技巧

  • 实时验证:如果希望用户切换国家时立刻验证已输入的邮编,可以开启Formik的enableReinitialize属性,或者用useEffect监听country字段变化,调用Formik的validateField('postalCode')方法手动触发验证。
  • 代码解耦:可以把邮编验证的逻辑抽成单独的函数,让代码更易维护:
const validatePostalCode = (postalValue, countryValue) => {
  const matchedRule = countryPostalRules.find(rule => rule.value === countryValue);
  return matchedRule ? matchedRule.postalRegex.test(postalValue) : true;
};

然后在Yup的test里直接调用这个函数即可。

内容的提问来源于stack exchange,提问作者Hans Poo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:35:49