做后台管理的时候, 常常会在弹窗里套一个表单
大部分情况下都会想在弹窗关闭的时候, 重置表单的数据
通用的解决方案
就是字面的意思, “弹窗关闭以后重置表单就好了”
<Modal afterClose={() => form.resetFields()}>
<Form >
</Modal>
不过之前我是不知道afterClose这个属性的
我会根据visible的值来判断弹窗是否关闭
如果用 class 组件, 可以在 componentDidUpdate做这个判断
componentDidUpdate(preProps) {
if (prevProps.visible && !this.props.visible) {
this.props.form.resetFiles()
}
}
如果是用 hooks, 我会粗暴一点, 直接
React.useEffect(() => {
if (!visible) {
form.resetFields()
}
}, [visible])
destroyOnClose
Modal 有一个 destroyOnClose 属性, 官方的解释是
关闭时销毁 Modal 里的子元素
很多人以为加了这个就行了, 但是得分情况讨论
如果用的是Antd 4
参考它的文档
<Modal />和 Form 一起配合使用时,设置destroyOnClose也不会在 Modal 关闭时销毁表单字段数据,需要设置<Form preserve={false} />。
也就是说, 像下面👇这样同时加上preserve={false}才行
<Modal destroyOnClose>
<Form preserve={false} >
</Modal>
可以参考这个issue, 里面有更多的讨论 github.com/ant-design/…
如果用的是Antd 3
很多时候确实是加了 destroyOnClose , 就可以了
但是如果使用自定义的表单控件, 会发现v3的官网有这么一段提示:
自定义或第三方的表单控件,也可以与 Form 组件一起使用。只要该组件遵循以下的约定:
- 提供受控属性
value或其它与valuePropName的值同名的属性。- 提供
onChange事件或trigger的值同名的事件。- 支持 ref:
- React@16.3.0 之前只有 Class 组件支持。
- React@16.3.0 及之后可以通过 forwardRef 添加 ref 支持。(示例)
第三点, 值得引起注意, 要支持ref
也就是说, 如果用函数式组件写了自定义的表单控件, 那么要注意 forwardRef 才行
antd 3 的表单底层用的是rc-form(antd 4用的是rc-field-form), 经过一番搜索, 发现了一个有趣的PR:
点进这个链接, 它的commit信息是
feat: getFieldDecorator support no ref component
通过查看这一楼层的评论和代码
可以发现, rc-form对于每一个field, 都会依靠ref来判断表单控件是否unmount, 如果unmount的话就进行重置表单字段值的操作
那么之前说的要支持ref, 就可以解释了
所以, 最后强调一下, 如果使用antd3(准确地说是3.26.20及以前的版本)并且用了function component来封装自定义的表单组件, 又要用destroyOnClose的话, 要forwardRef
其他
有一点我感觉比较奇怪, antd4 <Form /> 的 perserve 的默认值是 true , 但是底层用的rc-field-form 的默认值却是 false
在对应的 PR 里问了一下相关人员, 但是也没有得出很确切的结论. 我认为默认 false 会更符合直觉一些