react-hook-form如何实现两个表单项二选一的必填校验
实现二选一必填校验的方案
要实现两个字段至少填一个的校验逻辑,按以下步骤修改代码即可:
步骤1:调整useForm配置
从useForm中解构出getValues(用于获取其他字段的值)和formState.errors(用于展示错误提示),同时移除两个表单项上自带的required属性,因为我们要自定义校验规则,不需要原生的必填校验。
步骤2:封装自定义校验规则
我们可以封装一个通用的二选一必填校验函数,同时适配普通输入框和文件上传框的取值判断:
- 普通文本类字段判断是否为空字符串、是否全是空格
- 文件上传类字段判断选中的文件列表长度是否大于0
步骤3:绑定校验规则和错误提示
给每个Controller添加rules配置绑定校验逻辑,同时在表单项下方增加错误展示区域,让用户明确知道校验失败原因。
修改后的完整代码
import { useForm, Controller } from "react-hook-form"; import { Col, Row, Form, FormGroup, InputGroup, Input, Container, FormFeedback } from "reactstrap"; export default function App() { const onSubmit = (data) => { console.log(data); }; const { control, handleSubmit, getValues, formState: { errors } } = useForm({ mode: "onChange" // 可选,配置为onChange即可实时校验 }); // 通用二选一必填校验方法 const requireEither = (currentField, otherField, errorMsg) => { return (value) => { const otherValue = getValues(otherField); // 判断当前字段是否有有效值 let currentValid = !!value?.trim(); if (currentField === "itemlist2") { currentValid = value?.length > 0; } // 判断另一个字段是否有有效值 let otherValid = !!otherValue?.trim(); if (otherField === "itemlist2") { otherValid = otherValue?.length > 0; } // 两个字段都无有效值才返回错误 return currentValid || otherValid ? true : errorMsg; } } return ( <Container> <Form onSubmit={handleSubmit(onSubmit)}> <Row className="m-3"> <Col> <Controller name="itemlist" control={control} rules={{ validate: requireEither("itemlist", "itemlist2", "请至少填写itemlist或上传文件") }} render={({ field: { ref, ...field } }) => ( <div> <Input {...field} type="textarea" rows={10} placeholder="itemlist" innerRef={ref} invalid={!!errors.itemlist} /> {errors.itemlist && <FormFeedback>{errors.itemlist.message}</FormFeedback>} </div> )} /> </Col> </Row> <Row className="m-3"> <Col> <FormGroup row className="mr-md-1"> <InputGroup className="mb-3"> <Controller name="itemlist2" control={control} rules={{ validate: requireEither("itemlist2", "itemlist", "请至少上传文件或填写itemlist") }} render={({ field: { ref, ...field } }) => ( <div> <Input {...field} type="file" innerRef={ref} invalid={!!errors.itemlist2} /> {errors.itemlist2 && <FormFeedback>{errors.itemlist2.message}</FormFeedback>} </div> )} /> </InputGroup> </FormGroup> </Col> </Row> <button type="submit" className="btn btn-primary m-3">提交</button> </Form> </Container> ); }
补充说明
如果你的项目中已经接入了Yup、Zod等校验库,也可以直接在schema中配置条件必填逻辑,实现效果完全一致。上述封装的requireEither函数可以复用,后续有其他二选一必填的场景也可以直接调用。
内容的提问来源于stack exchange,提问作者Santhosh
相关产品推荐
相关产品推荐

