在Antd-Form 表單元件使用getValueFromEvent屬性為當前表單域賦值

yliboom發表於2018-04-22

目前專案中對錶單的使用較多,最近遇到了一個問題,大致描述:在表單域的onChange元件中無法使用setFields重置當前表單域的值.

  1. 發現問題
class App extends React.Component {
  handleChange = e => {
    const val = e.target.value.toUpperCase();
    this.props.form.setFieldsValue({
      userName: val
    });
  };

  render() {
    const { getFieldDecorator } = this.props.form;

    return (
      <Form onSubmit={this.handleSubmit}>
        <Form.Item
          labelCol={{ span: 5 }}
          wrapperCol={{ span: 12 }}
          label="字首"
        >
          {getFieldDecorator("userName")(
            <Input onChange={this.handleChange} />
          )}
        </Form.Item>
      </Form>
    );
  }
}

複製程式碼
  1. 進行嘗試:在onChange的回撥函式中利用setTimeout(func,0)[1]進行非同步賦值,類似情況出現在onChange回撥中利用form.getFieldsValue無法實時取值時。rc-form表單元件是通過setState的方式,將表單項封裝為受控元件。在onChange的回撥方法中,我們可以通過e.target.value拿到最新的值,此時,rc-form元件自身的賦值方法中並無法拿到這個最新的值,所以,進行同步並重新整理頁面值時,會把我們主動呼叫setFieldsValue方法傳入setState中的值覆蓋掉,所以使用非同步賦值的方法,可以解決我們這裡出現的值覆蓋情況。
class App extends React.Component {
   handleChange = e => {
    const val = e.target.value.toUpperCase();
    this.props.form.setFieldsValue({
      prefix: val,
      suffix: val + "2"
    });
  };

  render() {
    const { getFieldDecorator } = this.props.form;

    return (
      <Form onSubmit={this.handleSubmit}>
        <Form.Item {...formItemLayout} label="prefix">
          {getFieldDecorator("prefix")(<Input onChange={this.handleChange} />)}
        </Form.Item>
        <Form.Item {...formItemLayout} label="suffix">
          {getFieldDecorator("suffix")(<Input />)}
        </Form.Item>
      </Form>
    );
  }
}

複製程式碼
  1. 較之更優的方法-使用option.getValueFromEvent,進行賦值,相比之下,它更優雅而且不會造成二次渲染。
引數 說明 型別 預設值
option.getValueFormEvent 可以把onChange的引數轉化為控制元件的值(例如:Event) func(...args) e
class App extends React.Component {
  render() {
    const { getFieldDecorator } = this.props.form;
    const varsPrefixField = getFieldDecorator("prefix", {
      getValueFromEvent: e => e.target.value.toUpperCase()
    });
    return (
      <Form onSubmit={this.handleSubmit}>
        <Form.Item {...formItemLayout}
          label="字首"
        >
          {varsPrefixField(<Input />)}
        </Form.Item>
      </Form>
    );
  }
}


複製程式碼

備註:這裡的特殊情況出現在我們的表單域為自定義的InputGroup組合輸入框。

Refrence:

[1] “如果以0毫秒的超時時間來呼叫setTimeout(),那麼指定的函式不會立刻執行。相反,會把它放到佇列中,等到前面處於等待狀態的事件處理程式全部執行完成後,再“立即”呼叫它。”

摘錄來自: (美)David Flanagan. “JavaScript權威指南(原書第6版)”。 iBooks.

相關文章