问题背景:我在完成一个分步表单的功能的时候,在进行点击下一步的时候,会通过useEffect 来监听下一步或者上一步的动作,进行表单赋值,我使用 setFieldsValue 来进行整个赋值
useEffect(() => {
setFieldsValue(formValues);
}, [stepNum])
就会提示
Warning: You cannot set a form field before rendering a field associated with the value.
原因是我有一些字段是条件判断的,这个时候因为使用 getFieldDecorator 就会被注册到整个form,在这个时候表单设置值的时候没有这些字段,赋值的时候的时候就会异常提示。
解决方案:
使用 form.getFieldsValue 来获取当前项,然后对比赋值,最终在调用 setFieldsValue(obj)即可。这个时候obj就不包含其他未注册的值了
formValues 是收集到的每项表单的值。
Object.keys(form.getFieldsValue()).forEach(key => {
const obj = {};
obj[key] = formValues[key] || null;
setFieldsValue(obj)
})
补充:
第二个解决方案
通过CSS来控制隐藏 不展示在页面上的item,表单会收集到并且赋值,具体实现如下
<FormItem label="XXXX" style={{display:getFieldValue('X1') === '1'?"block":"none"}}>
{getFieldDecorator("X2", {
rules:getFieldValue('X1') === '1' && [{ required: true, message: "XXX" }],
})(<InputNumber min={1} max={12} placeholder='1~12' precision={0} />)}
</FormItem>
使用CSS来控制,结构不会销毁,所以可以收集到值,也就不会报上述错误了。
其次要注意的是,如果item是必填的,需要增加rules的判断,否则也会被验证到
其次是使用这个方案也可以减少性能开销.
第三个解决方案
使用setTimeout, 经过测试 发现基本需要延迟2秒才可以被真确赋值,此方案弊端较大,不确定性较大,所以不推荐。