React躬行記(7)——表單

  表單元素是一類擁有內部狀態的元素,這些狀態由其自身維護,經過這類元素可以讓用戶與Web應用進行交互。HTML中的表單元素(例如<input>、<select>和<radio>等)在React中都有相應的組件實現,不只如此,React還將它們分紅兩種:受控組件和非受控組件。html

1、受控組件

  受控組件(Controlled Component)是指那些受React控制的表單元素,其狀態(value、checked等屬性)的變動由組件的state管理。對於不一樣的表單元素,其受控組件的形式會有所差別,接下來會講解其中的三類。數組

1)文本框dom

  經常使用的單行文本框是一個type屬性爲「text」的<input>元素,它的值(即狀態)由value屬性控制。若是要監聽文本框的狀態變化,那麼能夠像下面這樣操做。函數

class Text extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: "init"};
    this.handle = this.handle.bind(this);
  }
  handle(e) {
    this.setState({value: e.target.value.toUpperCase()});
  }
  render() {
    return <input value={this.state.value} onChange={this.handle} type="text" />;
  }
}

  上述代碼實現了一個簡單的功能,在改變文本框中的內容時,自動將其轉換成大寫字母。具體的更新過程可分爲四步:this

(1)在構造函數中初始化組件的state,併爲文本框設置默認值。spa

(2)文本框註冊onChange事件,監聽其值的變化。code

(3)在事件處理程序handle()中,經過e.target.value讀取到輸入的值,修改並同步(調用this.setState()方法)到組件的state中。htm

(4)組件從新渲染,完成文本框的內容更新。對象

  其餘兩類受控組件的更新過程與之相似,只是在細節處理上有所不一樣。blog

  觀察上面的示例能夠發現,文本框的數據來源於組件的state,經過onChange事件將輸入的新數據再同步給組件的state,從而完成了一次雙向數據綁定。

  React中的<textarea>元素(多行文本框),其使用相似於上面的<input>元素,也是經過value屬性來獲取值的,以下代碼所示,省略了構造函數和事件處理程序。

class TextArea extends React.Component {
  render() {
    return <textarea value={this.state.value} onChange={this.handle} />;
  }
}

  而HTML中的<textarea>元素則會將值定義成子元素,而且包含結束標籤,以下所示。

<textarea>init</textarea>

2)單選框和複選框

  單選框是一個type屬性爲「radio」的<input>元素,複選框是一個type屬性爲「checkbox」的<input>元素。與以前的文本框不一樣,React控制的不是它們的值,而是選中狀態,即布爾屬性checked。在下面的例子中,監聽了每一個單選框的checked屬性。

class Radio extends React.Component {
  constructor(props) {
    super(props);
    this.state = { gender: "" };
    this.handle = this.handle.bind(this);
  }
  handle(e) {
    this.setState({
      gender: e.target.value
    });
  }
  render() {
    return (
      <>
        <input name="gender" value="1" onChange={this.handle} type="radio" 
          checked={this.state.gender == "1"}
        />男
        <input name="gender" value="2" onChange={this.handle} type="radio"
          checked={this.state.gender == "2"}
        />女
      </>
    );
  }
}

  複選框能選中多個項,其操做要比單選框繁瑣許多。在下面的例子中,不但監聽了每一個複選框的checked屬性,還將處於選中狀態的值提取了出來,組成一個數組。

class Checkbox extends React.Component {
  constructor(props) {
    super(props);
    this.state = { colors: [] };        //保存複選框值的數組
    this.handle = this.handle.bind(this);
  }
  handle(e) {
    const { checked, value } = e.target;
    let { colors } = this.state;
    if (checked && colors.indexOf(value) == -1) {
      colors.push(value);            //已選中而且數組中未有該值,就在末尾插入
    } else {    
      colors = colors.filter(item => item != value);        //未選中,就將該值過濾掉
    }
    this.setState({ colors });
  }
  render() {
    return (
      <>
        <input name="colors" value="1" onChange={this.handle} type="checkbox"
          checked={this.state.colors.indexOf("1") >= 0}
        />紅
        <input name="colors" value="2" onChange={this.handle} type="checkbox"
          checked={this.state.colors.indexOf("2") >= 0}
        />綠
        <input name="colors" value="3" onChange={this.handle} type="checkbox"
          checked={this.state.colors.indexOf("3") >= 0}
        />藍
      </>
    );
  }
}

  雖然React處理單選框和複選框的方式要比在HTML中複雜一點,可是保證了組件的state是元素狀態的惟一來源,進而讓更新過程更加可靠和可控。

3)選擇框

  在HTML中,<select>元素(選擇框)會包含多個用來表示選項的<option>元素,而選中的項會被定義一個selected屬性,以下代碼所示,第二個<option>元素處於選中狀態。

<select>
  <option value="1">strick</option>
  <option value="2" selected>freedom</option>
  <option value="3">jane</option>
</select>

  在React中,只需對<select>元素定義value屬性就能決定當前的選中項,以下代碼所示,這比用DOM的方式操做選項要簡潔得多。

class Select extends React.Component {
  constructor(props) {
    super(props);
    this.state = { value: "" };
    this.handle = this.handle.bind(this);
  }
  handle(e) {
    this.setState({ value: e.target.value });
  }
  render() {
    return (
      <select value={this.state.value} onChange={this.handle}>
        <option value="1">strick</option>
        <option value="2">freedom</option>
        <option value="3">jane</option>
      </select>
    );
  }
}

  只要給<select>元素添加multiple屬性並將其賦爲true就能變爲多選,以下代碼所示,此時傳給value屬性的是一個數組。

class MulSelect extends React.Component {
  constructor(props) {
    super(props);
    this.state = { values: [] };
    this.handle = this.handle.bind(this);
  }
  handle(e) {
    const { options } = e.target;             //options是一個類數組對象
    const values = Object.keys(options)       //將options的索引組成一個數組
      .filter(i => options[i].selected)       //過濾出選中項
      .map(i => options[i].value);            //提取選中項組成新數組
    this.setState({ values });
  }
  render() {
    return (
      <select value={this.state.values} onChange={this.handle} multiple={true}>
        <option value="1">strick</option>
        <option value="2">freedom</option>
        <option value="3">jane</option>
      </select>
    );
  }
}

2、非受控組件

  非受控組件(Uncontrolled Component)的定義正好與受控組件的相左,其狀態由本身管理,一般使用ref屬性(第5篇中講解過)獲取表單元素的值。在下面的示例中,文本框在失去焦點時,能自動將其內容轉換成大寫字母。若是用受控組件的形式完成相同的功能,那麼會較爲繁瑣。

class Text extends React.Component {
  constructor(props) {
    super(props);
    this.handle = this.handle.bind(this);
  }
  handle() {
    this.input.value = this.input.value.toUpperCase();
  }
  render() {
    return <input onBlur={this.handle} type="text" ref={ input => {this.input = input}}/>;
  }
}

  在render()方法中,首先爲文本框註冊onBlur事件,而後定義ref屬性,其值是一個回調函數。當組件被掛載時,就會執行該回調函數,而後就能讓this.input指向一個文本框,從而在事件處理程序handle()中就能經過this.input讀取到文本框中的內容。

  在React中,有一個表單元素比較特殊,那就是上傳按鈕。它只有非受控組件的形式,由於其值只能由用戶傳入,不能被組件的state所控制。

1)默認值

  若是要指定非受控組件的默認值,那麼可經過定義defaultValue或defaultChecked屬性實現,前者適用於文本框、選擇框等元素,後者適用於單選框和複選框。下面的示例分別給文本框和單選框設置了默認值,爲了便於觀察,只放出了關鍵代碼。

class Text extends React.Component {
  render() {
    return <input type="text" defaultValue="init"/>;
  }
}
class Radio extends React.Component {
  render() {
    return (
      <>
        <input name="gender" value="1" type="radio"/>男
        <input name="gender" value="2" type="radio" defaultChecked={true}/>女
      </>
    );
  }
}
相關文章
相關標籤/搜索