1. 程式人生 > >淺析React中的受控元件和非受控元件

淺析React中的受控元件和非受控元件

React中的受控和非受控表單並不複雜

這裡寫圖片描述
你可能看到過很多文章,說不應該使用setStaterefs不好……這是自相矛盾的。很難理解怎樣是對的,甚至連選擇的規則都不清楚。

那我們應該怎麼解決表單這個棘手的問題呢?

畢竟表單還是某些web應用的核心。可是處理表單好像變成了絆腳石?

不用害怕了。我會告訴你這兩種方式的區別和使用場景。

The Uncontrolled

非控表單輸入類似於傳統的HTML表單輸入:

class Form extends Component{
    render(){
        return (
            <div>
                <input
type="text" />
</div> ); } }

他們記得你輸入了什麼。你可以使用ref獲取他們的值。例如,在按鈕的onClick處理方法中:

class Form extends Component {
  handleSubmitClick = () => {
    const name = this._name.value;
    // do something with `name`
  }

  render() {
    return (
      <div>
        <input
type="text" ref={input =>
this._name = input} /> <button onClick={this.handleSubmitClick}>Sign up</button> </div> ); } }

換句話說,你要在自己需要的時候從表單域中拉取相應的值。這可能發生在表單提交的時候。

那是實現表單輸入的最簡單的方法。下面是一些有效的使用場景:在現實世界中的簡單表單,還有在學React的時候。

不過它並不是很強大,接下來讓我們看看受控表單。

The Controlled

受控表單接收當前值作為屬性,或者作為改變其值的呼叫。可以說它是一種更“React”的方式(但並不意味著總是用它)。

<input value={someValue} onChange={handleChange} />

這很好,但是輸入的值不得不儲存在某個地方的state裡。典型的是,渲染input(又稱表單元件)的元件要在其state中儲存該值:

class Form extends Component {
  constructor() {
    super();
    this.state = {
      name: '',
    };
  }

  handleNameChange = (event) => {
    this.setState({ name: event.target.value });
  };

  render() {
    return (
      <div>
        <input
          type="text"
          value={this.state.name}
          onChange={this.handleNameChange}
        />
      </div>
    );
  }
}

(當然,還可能儲存在其他元件的state裡,或者一些單獨的狀態儲存像Redux中。)

每次輸入新字元時,都會呼叫handleNameChange。它接收輸入的新值,並把它放到state中。

這裡寫圖片描述

  • 首先是空字串
  • 當你輸入a時,handleNameChange會取得a,並呼叫setState。輸入表單的值就會重渲染為a。
  • 你輸入了b,handleNameChange獲取到ab的值,並把它設定到state中。然後輸入域的值就再一次被渲染成ab。

這種方式把值推送給表單元件,因此Form元件總是會有當前輸入的值,而不必顯示請求。

這意味著你的資料(state)和UI(inputs)總是同步的。狀態給輸入元件以值 ,使用者的輸入又促使Form元件改變當前的值。

這也意味著表單元件會立即響應輸入的改動,如以下場景:

  • 及時反饋,像驗證
  • 使按鈕處於不可用狀態,除非表單域都有有效值
  • 強制特定輸入格式,像信用卡號

但是如果你不需要這些,那就考慮更簡單的非受控元件吧。

What makes an element “controlled”

當然有其他表單元素。你可能使用多選框、單選按鈕、選擇列表和文字域等。

當通過prop設定這些元件的值時,他們就變成了受控元件。

不過,元件使用不同的屬性值來設定他們的值,這總結了一個表格:

Element Value property Change callback New value in the callback
<input type="text" /> value="string" onChange event.target.value
<input type="checkbox" /> checked={boolean} onChange event.target.checked
<input type="radio" /> checked={boolean} onChange event.target.checked
<textarea /> value="string" onChange event.target.value
<select /> value="option value" onChange event.target.value

Conclusion

受控和非受控表單域各有各的優勢。具體情況具體分析來選擇適合自己的方式。

如果你的表單非常簡單,只依賴UI反饋,帶refs的非受控元件就可以完成的很好,而不用在意那些說這樣不好的文章。

而且,這並不是一次性決定,你可以總是遷移到受控輸入上。從非受控元件遷移到受控元件並不難

References