8.Forms(表單)

React版本:15.4.2
**翻譯:xiyoki **

在React中,HTML表單元素的工作方式與其他DOM元素的工作方式有點(diǎn)不同。因?yàn)楸韱卧刈匀话恍﹥?nèi)部狀態(tài)。例如,這種采用純HTML格式的表單接受單個(gè)名稱:

<form>
  <label>
    Name:
    <input type="text" name="name" />
  </label>
  <input type="submit" value="Submit" />
</form>

這個(gè)表單具有在用戶提交表單時(shí)瀏覽到新頁(yè)面的默認(rèn)HTML表單行為。在React中,表單的這一行為也是會(huì)發(fā)揮作用的。但在大多數(shù)情況下,使用Javascript函數(shù)處理表單的提交并訪問(wèn)用戶在表單中輸入的數(shù)據(jù)是很方便的。實(shí)現(xiàn)這一點(diǎn)的標(biāo)準(zhǔn)方法是使用被稱為“受控組件”的技術(shù)。

Controlled Components(受控組件)

在HTML中,表單元素如<input>,<textarea>以及<select>通常保持自己的狀態(tài),并根據(jù)用戶輸入進(jìn)行更新。在React中,可變的狀態(tài)通常保持在組件的state屬性上,并且只能通過(guò)setState()方法進(jìn)行更新。
我們可以通過(guò)把React狀態(tài)變成“唯一真實(shí)的來(lái)源”來(lái)結(jié)合二者。然后,渲染表單的React組件也將控制在用戶輸入后在表單上發(fā)生的事情。其值由React以這種方式進(jìn)行控制的輸入表單元素被稱為“受控組件”。
例如,如果我們想讓上一個(gè)示例在表單被提交時(shí)打印name字段的值,我們可以將表單寫成受控組件。

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

由于value屬性設(shè)置在表單元素上,顯示的值將始終是this.state.value,使得React state成了真實(shí)的來(lái)源。由于handleChange在每次擊鍵后更新React 狀態(tài),顯示的值將更新為用戶類型。
使用受控組件,每個(gè)狀態(tài)變量都具有關(guān)聯(lián)的處理函數(shù)。這便能直接修改或驗(yàn)證用戶輸入。例如,我們強(qiáng)制要Name字段為大寫字母書寫格式,我們可以寫handleChange為:

handleChange(event) {
    this.setState({value: event.target.value.toUpperCase()});
}

The textarea Tag(textarea標(biāo)簽)

在HTML中,<textarea>元素的文本由其子元素定義:

<textarea>
  Hello there, this is some text in a text area
</textarea>

在React中,<textarea>使用value屬性來(lái)代替。這種方式下,使用了<textarea>的表單的寫法與使用單行輸入框的表單的寫法非常相似:

class EssayForm extends React.Component {
  constructor(props) {
    super(props);
      this.state = {
        value: 'Please write an essay about your favorite DOM element.'
      };

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('An essay was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <textarea value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

注意,this.state.value在構(gòu)造函數(shù)中被初始化了,因此文本區(qū)域中是有一些文字的。

The select Tag(選擇標(biāo)簽)

在HTML中,<select>創(chuàng)建一個(gè)下拉列表。例如此HTML創(chuàng)建了一個(gè)下拉列表:

<select>
  <option value="grapefruit">Grapefruit</option>
  <option value="lime">Lime</option>
  <option selected value="coconut">Coconut</option>
  <option value="mango">Mango</option>
</select>

需要注意的是,Coconut選項(xiàng)最初的時(shí)候被選擇了,因?yàn)?code>selected屬性。在React中,不會(huì)使用selected屬性,而是在根select標(biāo)簽上添加value屬性來(lái)代替。這在受控組件中更方便,因?yàn)槟阒恍枰谝粋€(gè)地方更新它。例如:

class FlavorForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: 'coconut'};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('Your favorite flavor is: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Pick your favorite La Croix flavor:
          <select value={this.state.value} onChange={this.handleChange}>
            <option value="grapefruit">Grapefruit</option>
            <option value="lime">Lime</option>
            <option value="coconut">Coconut</option>
            <option value="mango">Mango</option>
          </select>
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

總的來(lái)說(shuō), 這樣使得<input type="text">, <textarea>,<select>的工作都相似,它們都接受value屬性,你可以使用它來(lái)實(shí)現(xiàn)一個(gè)受控組件。

Handling Multiple Inputs(處理多個(gè)Inputs)

當(dāng)你需要處理多個(gè)受控的input元素,你可以為每個(gè)元素添加一個(gè)name屬性,讓處理函數(shù)基于event.target.name的屬性值來(lái)選擇后續(xù)該做什么。
例如:

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      numberOfGuests: 2
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;  //獲取表單控件的屬性值
    const name = target.name;

    this.setState({
      [name]: value 
    });
  }

  render() {
    return (
      <form>
        <label>
          Is going:
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} 
          />
        </label>
        <br />
        <label>
          Number of guests:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} 
          />
        </label>
      </form>
    );
  }
}

注意,我們是如何使用ES6的 computed property name 語(yǔ)法來(lái)更新對(duì)應(yīng)到給定輸入框名稱的狀態(tài)鍵名的:

this.setState({
  [name]: value
});

它等同于如下ES5代碼:

var partialState = {};
partialState[name] = value;
this.setState(partialState);

此外,由于setState()自動(dòng)merges a partial state into the current state,我們只需要在調(diào)用它時(shí)傳入已更改的部分。

Alternatives to Controlled Components(受控組件的替代方案)

使用受控組件有時(shí)候可能很乏味,因?yàn)槟阈枰獮閿?shù)據(jù)能夠更改的每條路徑編寫事件處理程序,并且在React組件中pipe輸入state的全部。當(dāng)將預(yù)先存在的代碼庫(kù)轉(zhuǎn)換為React或?qū)eact應(yīng)用程序與非React庫(kù)集成時(shí),這可能會(huì)變得特別煩人。在這些情況下,你可能要檢查出不受控制的組件,實(shí)現(xiàn)輸入表單的替代技術(shù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容