Formik结合Yup与Semantic UI实现表单条件校验问题咨询
问题根源
现有校验规则对Facebook、Instagram的关联字段直接设置了全局必填,没有根据平台选中状态动态调整校验逻辑,同时组件存在表单状态重复维护、渲染判断不一致、漏加Instagram链接字段校验的问题,才会出现无论选不选对应平台都强制校验所有字段的情况。
修复方案
1. 重写Yup校验规则,用when实现条件校验
通过Yup内置的when方法监听平台选中字段的值,只有当对应平台被选中时,才启用关联字段的必填规则,修改后的校验代码如下:
import * as yup from 'yup'; export const ProfessionalValidation = yup.object().shape({ // 分类字段保留原有必填规则 category: yup.array().required('Category Name is required').nullable(), // 平台选择字段设置最少选1项的规则 platform: yup.array().min(1, 'At least One Platform is required').required('At least One Platform is required').nullable(), // Facebook关联字段:仅当选中Facebook时才必填 facebookLink: yup.string().when('platform', { is: (platform) => Array.isArray(platform) && platform.includes('Facebook'), then: (schema) => schema.required('Facebook account link is required'), otherwise: (schema) => schema.notRequired() }).nullable(), FBfollowers: yup.string().when('platform', { is: (platform) => Array.isArray(platform) && platform.includes('Facebook'), then: (schema) => schema.required('Please select your Facebook follower count'), otherwise: (schema) => schema.notRequired() }).nullable(), // Instagram关联字段:仅当选中Instagram时才必填 InstaLink: yup.string().when('platform', { is: (platform) => Array.isArray(platform) && platform.includes('Instagram'), then: (schema) => schema.required('Instagram account link is required'), otherwise: (schema) => schema.notRequired() }).nullable(), Instafollowers: yup.string().when('platform', { is: (platform) => Array.isArray(platform) && platform.includes('Instagram'), then: (schema) => schema.required('Please select your Instagram follower count'), otherwise: (schema) => schema.notRequired() }).nullable(), })
注意:原代码漏写了
InstaLink字段的校验规则,上述代码已补全,同时修正了原提示文本的拼写错误。
2. 修复组件逻辑bug
原组件单独维护了selectedOptions本地状态,和Formik内部管理的values.platform状态重复,很容易出现状态不同步的问题,且Instagram模块的渲染判断逻辑和Facebook不一致,需要同步调整:
- 删除冗余的
selectedOptions、savedata本地状态,所有表单值统一交给Formik管理 - 多选字段的初始值从空字符串改为空数组,避免调用数组方法时报错
- 统一用
values.platform判断平台是否选中,补全缺失的提交方法、Instagram链接字段的错误提示
修改后的核心组件代码如下:
import { useState } from 'react'; import { ProfessionalValidation } from "./Validation"; import { ErrorMessage, Formik, Form, Field } from "formik"; import { categoryOptions, Platform, followers, } from "./Data"; import { Dropdown } from "semantic-ui-react"; import "./style.css"; import "./styles.css"; const UserInfo = () => { const defaultValue = { category: [], platform: [], facebookLink: "", InstaLink: "", Instafollowers: "", FBfollowers: "", subscribers: "", youtube: "" }; const handleSubmit = (values) => { console.log('表单提交值', values); // 此处编写提交逻辑 } return ( <Formik initialValues={defaultValue} validationSchema={ProfessionalValidation} onSubmit={handleSubmit} > {({ values, setFieldValue }) => ( <Form> <section className="form-styling my-4"> <div className="container"> <div className="input-box2"> <div> <label htmlFor="category">Category*</label> <Field clearable name="category" fluid multiple search selection options={categoryOptions} component={Dropdown} placeholder="Select Category" onChange={(_, { value }) => setFieldValue("category", value)} /> <span style={{ color: "red" }}> <ErrorMessage name="category" /> </span> </div> <div> <label htmlFor="platform">Platform*</label> <Field clearable name="platform" fluid multiple search selection options={Platform} placeholder="Select Platform" component={Dropdown} onChange={(_, { value }) => setFieldValue("platform", value)} /> <span style={{ color: "red" }}> <ErrorMessage name="platform" /> </span> <span className="mt-3 d-block">Select at least 1</span> </div> </div> <div className="platform-box"> <div> {values.platform.includes("Facebook") ? ( <div> <div className="platform-details"> <div> <h5>Facebook</h5> </div> <div> <Field type="text" name="facebookLink" placeholder="Account Link" /> <span className="text-danger"> <ErrorMessage name="facebookLink" /> </span> </div> <div> <Field className="label ui selection fluid dropdown" clearable name="FBfollowers" fluid search selection options={followers} component={Dropdown} placeholder="Select followers" onChange={(_, { value }) => setFieldValue("FBfollowers", value)} /> <span className="text-danger"> <ErrorMessage name="FBfollowers" /> </span> </div> </div> <span>Verify the Followers in 2-3 Business Days</span> </div> ) : null} {values.platform.includes("Instagram") ? ( <div> <div className="platform-details"> <div> <h5>Instagram</h5> </div> <div> <Field type="text" name="InstaLink" placeholder="Account Link" /> <span className="text-danger"> <ErrorMessage name="InstaLink" /> </span> </div> <div> <Field className="label ui selection fluid dropdown" clearable name="Instafollowers" fluid search selection options={followers} component={Dropdown} placeholder="Select followers" onChange={(_, { value }) => setFieldValue("Instafollowers", value)} /> <span style={{ color: "red" }}> <ErrorMessage name="Instafollowers" /> </span> </div> </div> <span>Verify the Followers in 2-3 Business Days</span> </div> ) : null} </div> </div> </div> </section> <section className="additional-Info "> <div className="container"> <div className="main-box"></div> <div className="text-start my-5"> <button type="submit" className="border-0"> <span className="btn-form btn btn-info">Continue</span> </button> </div> </div> </section> </Form> )} </Formik> ); }; export default UserInfo;
最终效果
- 未选中任何平台时,仅提示平台字段必填,不会触发平台关联字段的校验
- 选中单个平台时,仅校验对应平台的账号链接、粉丝数字段,未选中平台的字段无校验要求
- 同时选中多个平台时,所有选中平台的关联字段都触发必填校验
- 取消选中某平台时,对应字段的校验规则自动移除,不会残留校验报错
内容的提问来源于stack exchange,提问作者kanu das
相关产品推荐
相关产品推荐

