Antd 4 Form resetFields无效

简介

使用Ant Design 4Form表单实例的resetFields方法重置表单数据时没有产生理想的重置效果。

我的项目逻辑:使用一个Antd提供的Table表格组件渲染一堆数据,并在表格的最后一列展示几个操作该行数据按钮。点击操作数据的按钮后使用Modal组件显示一个表单对话窗让用户修改数据。Modal组件中的表单Form组件拿到该行数据进行初始化,让用户方便修改。

问题:用户第一次点击修改按钮弹出Modal组件后,表单正常初始化数据;第二次点击另外一行进行修改时,表单初始化的数据仍是上一次点击行的数据;第三次点击另一行后表单的初始化数据为第二次点击行的数据。

案例代码

按照简介中的项目逻辑写了一个精简案例:

import React, { Component, Fragment } from 'react'
import { Button, Table, Modal, Form, Input } from 'antd'

const { Item } = Form
// Table组件 表格每行数据
const dataSource = [
  { key: 1, name: 'Tom' },
  { key: 2, name: 'Bob' },
  { key: 3, name: 'Kevin' },
  { key: 4, name: 'Jack' },
  { key: 5, name: 'Jay' }
]

class Example extends Component {
  state = {
    visible: false,
    name: ''
  }

  // Table组件 表格列的配置
  columns = [
    {
      title: '名称',
      dataIndex: 'name'
    },
    {
      title: '操作',
      render: item => (
        <Button type='link' onClick={() => this.initModal(item)}>修改名称</Button>
      )
    }
  ]

  initModal = item => {
    this.setState({
      visible: true,
      name: item.name
    })
  }

  changeModalVisible = () => {
    this.refs.form.resetFields()
    this.setState({
      visible: !this.state.visible
    })
  }

  handleOk = () => {
    // ...
    // 省略表单处理代码
    this.changeModalVisible()
  }

  render() {
    const { visible, name } = this.state
    return (
      <Fragment>
        <Table dataSource={dataSource} columns={this.columns} rowKey='key' />
        <Modal
          title='修改名称'
          visible={visible}
          onOk={this.handleOk}
          onCancel={this.changeModalVisible}
        >
          <Form ref='form' initialValues={{ name: name }}>
            <Item name='name'>
              <Input />
            </Item>
          </Form>
        </Modal>
      </Fragment>
    )
  }
}

export default Example

运行效果

resetfields-problem

分析问题

第一次点击能正常初始化表单;第二次点击,表单的数据为第一次点击的数据;第三次点击,表单初始化的数据为第二次的值。

我首先想到了resetFields重置表单这个方法使用的时机存在问题,表单的重置应该在每一次点击表格中修改名称按钮后显示Modal时,但是这样处理的话,第一次显示Modal通过this.refs.form获取不到表单实例:

initModal = item => {
  // 应该在表单中按钮触发显示Modal的操作
  // 在 setState 函数的回调中执行重置操作,保证Modal的visible状态已经改变
  this.setState({
    visible: true,
    name: item.name
  }, () => this.refs.form.resetFields())
}

changeModalVisible = () => {
  // 不应该在这里重置表单
  // this.refs.form.resetFields()
  this.setState({
    visible: !this.state.visible
  })
}

出现报错:

Example.js Uncaught TypeError: Cannot read property 'resetFields' of undefined

说明this.refs.formundefined,没有拿到form实例,所有没有resetFields方法。

打开React Developer Tools发现Modal组件在最开始visible属性为false时是没有初始化的,第一次点击表单按钮改变Modalvisible后才得到加载。

react-modal

然后我找了一下Modal没有初始化完后触发事件的接口,所以我就直接加一个if判断吧:

initModal = item => {
  // 应该在表单中按钮触发显示Modal的操作
  // 在 setState 函数的回调中执行重置操作,保证Modal的visible状态已经改变
  this.setState({
    visible: true,
    name: item.name
  }, () => {
    const { form } = this.refs
    if (form) form.resetFields()
  })
}

可以了,这样就达到了正常的表单重置效果。

result

补充

对于上面简单的逻辑,我觉得将表单重置放在componentDidUpdate生命周期里也是可以的:

initModal = item => {
  this.setState({
    visible: true,
    name: item.name
  }, () => {
    // const { form } = this.refs
    // if (form) form.resetFields()
  })
}

componentDidUpdate() {
  const { form } = this.refs
  if (form) form.resetFields()
}

resetFields 方法

对于Antd提供的重置表单的方法,和传统原生的JS中form表单的type="reset"的效果不同,它并不是清空表单,而是重置到Form组件的initialValues属性的值,如果没有initialValues属性当然就重置为空,也就是清空表单。


版权声明:

Anand's Blog文章皆为站长Anand Zhang原创内容,转载请注明出处。

包括商业转载在内,注明下方要求的文章出处信息即可,无需联系站长授权。

请尊重他人劳动成果,用爱发电十分不易,谢谢!

请注明出处:

本文出自:Anand's Blog

本文永久链接:https://anandzhang.com/posts/frontend/13