Redux Form中所有topic字段批量显示校验错误的问题排查
嘿,我一眼就看出问题的核心所在了:你给Redux Form里所有同类型的<Field>都用了一模一样的name属性(比如所有主题名称字段都叫topic_name)。Redux Form的校验错误是和name绑定的,只要这个name对应的字段校验失败,所有用这个name的输入框都会同步显示错误提示,这就是为什么改一个字段时,所有同名字段都弹出必填提示的原因。另外你自己还维护了组件内的state来存字段值,这和Redux Form的状态管理冲突了,也是onChange校验不符合预期的诱因之一。
下面是具体的解决步骤,咱们一步步来:
1. 给每个字段分配唯一的name
咱们得让每个输入框的name独一无二:
- 新增主题的输入框,用
new_topic_name和new_topic_type这类固定唯一的name; - 已存在的自定义主题,根据每条数据的ID或者索引生成name,比如
topic_name_${obj.id}、topic_type_${obj.id},这样每条数据的字段都不会互相干扰。
2. 更新校验逻辑适配唯一字段名
原来的校验函数只检查固定的topic_name和topic_type,现在要改成能识别所有唯一字段的逻辑:
export const validate = values => { const errors = {}; // 校验新增的主题字段 const requiredNewFields = { new_topic_name: 'Topic Name', new_topic_type: 'Topic Type', }; for (const key in requiredNewFields) { if (requiredNewFields.hasOwnProperty(key) && !values[key]) { errors[key] = `${requiredNewFields[key]} is required`; } } // 校验已存在的主题字段 Object.keys(values).forEach(key => { // 匹配所有topic_name_开头的字段 if (key.startsWith('topic_name_') && !values[key]) { errors[key] = 'Topic Name is required'; } // 匹配所有topic_type_开头的字段 if (key.startsWith('topic_type_') && !values[key]) { errors[key] = 'Topic Type is required'; } }); return errors; };
3. 移除组件内的state,让Redux Form接管状态
删掉你组件里自己维护的topic_name、topic_type这些state,改用Redux Form提供的this.props.values来获取字段值,同时去掉自定义的handleChange——Redux Form会自动处理字段的onChange事件,不用咱们自己管。
4. 修改Field组件的配置
新增主题的Field:
<Field placeholder="Topic Name" name="new_topic_name" id="new_topic_name" className="input-field" type="text" fullWidth component={TopicNameField} required />
<Field placeholder="Topic Type" name="new_topic_type" id="new_topic_type" required className="input-field" type="text" fullWidth component={TopicTypeField} />
已有主题的Field(遍历自定义主题时):
{topics && topics.customTopic.map((obj, i) => ( <TableRow key={obj.id} id={obj.id}> <TableColumn> <Field placeholder="Topic Name" name={`topic_name_${obj.id}`} id={`topic_name_${obj.id}`} defaultValue={obj.topic_name} onBlur={(e, dispatch, props) => { // 从Redux Form的props.values里拿当前字段值 this.updateCustomTopic( { topic_name: props.values[`topic_name_${obj.id}`] }, obj.id ); }} required className="input-field" type="text" fullWidth component={TopicNameField} /> </TableColumn> <TableColumn> <Field placeholder="Topic Type" name={`topic_type_${obj.id}`} id={`topic_type_${obj.id}`} defaultValue={obj.topic_type} onBlur={(e, dispatch, props) => { this.updateCustomTopic( { topic_type: props.values[`topic_type_${obj.id}`] }, obj.id ); }} required className="input-field" type="text" fullWidth component={TopicTypeField} /> </TableColumn> <TableColumn> <Button icon tooltipLabel="Delete" onClick={() => this.show(obj.id)}> delete </Button> </TableColumn> </TableRow> ))}
5. 调整新增主题的逻辑
在addCustomTopic方法里,从Redux Form的props.values中获取新增字段的值,新增后记得重置字段:
addCustomTopic = (e) => { e.preventDefault(); const { values, resetSection } = this.props; const newTopic = { topic_name: values.new_topic_name, topic_type: values.new_topic_type }; // 调用你的新增主题action this.props.addCustomTopic(newTopic); // 重置新增字段 resetSection('new_topic_name'); resetSection('new_topic_type'); };
额外要注意的点
- 确保你的
TopicNameField和TopicTypeField组件正确处理Redux Form传递的meta.error和meta.touched属性,只在字段被触碰且有错误时显示提示,避免一开始就显示错误:const TopicNameField = ({ input, placeholder, meta: { touched, error } }) => ( <div> <input {...input} placeholder={placeholder} className="input-field" /> {touched && error && <span style={{color: 'red'}}>{error}</span>} </div> ); - 如果需要从URL参数获取初始值(比如
props.match.params.topic),可以在Redux Form的initialValues里设置,不用组件state:export default reduxForm({ form: 'wizard', validate, initialValues: (props) => ({ new_topic_name: props.match.params.topic || '' }) })(connect(mapStateToProps, mapDispatchToProps)(Topic));
内容的提问来源于stack exchange,提问作者Serenity
相关产品推荐
相关产品推荐

