文章

受控與非受控元件

受控與非受控元件

在 React 中,表單元素(如 <input><textarea><select> 等)可以有兩種不同的方式來管理其狀態:受控元件(Controlled Components)非受控元件(Uncontrolled Components)

1. 受控元件

受控元件是指其值完全由 React 控制。表單元素的值存儲在組件的 state 中,並且當用戶進行輸入時,通過事件處理程序來更新狀態。這使得我們可以更方便地控制和驗證表單數據。

範例:受控的 <input> 元件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class ControlledInput extends React.Component {
  constructor(props) {
    super(props);
    this.state = { value: '' };
  }

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

  handleSubmit = (event) => {
    alert('輸入的值: ' + this.state.value);
    event.preventDefault();
  };

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          輸入文字:
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <button type="submit">提交</button>
      </form>
    );
  }
}

export default ControlledInput;

在這個例子中:

  • input 的值是由 state 中的 value 屬性控制。
  • 當用戶輸入時,觸發 onChange 事件處理程序來更新 state,從而使得 input 的顯示值始終和 state 保持同步。

受控元件的優點:

  • 數據集中管理:所有表單數據都存儲在組件的 state 中,便於集中管理和處理。
  • 便於數據驗證:可以在數據改變的同時進行驗證,比如限制輸入的字數或格式。
  • 靈活的數據流控制:表單的數據流是單向的,方便進行邏輯處理和狀態變更。

2. 非受控元件

非受控元件不將表單的值儲存在 React 的 state 中,而是直接通過 DOM 來管理表單的值。你可以使用 React 的 ref 來獲取 DOM 元素的值,而不需要通過 state 來更新表單數據。

範例:非受控的 <input> 元件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class UncontrolledInput extends React.Component {
  constructor(props) {
    super(props);
    this.inputRef = React.createRef();
  }

  handleSubmit = (event) => {
    alert('輸入的值: ' + this.inputRef.current.value);
    event.preventDefault();
  };

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          輸入文字:
          <input type="text" ref={this.inputRef} />
        </label>
        <button type="submit">提交</button>
      </form>
    );
  }
}

export default UncontrolledInput;

在這個例子中:

  • 我們使用 React.createRef() 創建了一個 ref,並將它賦值給 input 元件。
  • 當表單提交時,通過 ref 獲取 input 的值,而不需要通過 state 來存儲或控制。

非受控元件的優點:

  • 簡單的實現:如果表單的邏輯很簡單,使用非受控元件會更容易,因為你不需要管理 state
  • 適用於低頻次更新:當表單的值不需要頻繁更新或驗證時,非受控元件可以簡化代碼。

3. 受控與非受控元件的區別

特性受控元件非受控元件
數據來源表單的值由 React 的 state 控制。表單的值直接存儲在 DOM 中。
值的改變需要通過 onChange 事件來更新 state不需要更新 state,可以通過 ref 獲取值。
適用場景當需要頻繁更新表單數據或進行即時驗證時。表單邏輯簡單、不需要頻繁操作或即時驗證時。
數據流控制更嚴格的數據流控制,便於數據管理和處理。較弱的數據流控制,無需管理 state
表單驗證更容易實現表單驗證和其他控制邏輯。需要手動在事件處理器中實現驗證。

4. 受控與非受控的混合使用

有時候,你可能會需要在同一個表單中同時使用受控元件和非受控元件。例如,你可能需要將某些輸入的值直接保存在 DOM 中,而其他的輸入值則需要通過 React 的 state 來管理。

範例:混合使用受控和非受控元件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class MixedForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = { name: '' };
    this.ageInputRef = React.createRef();
  }

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

  handleSubmit = (event) => {
    alert('名稱: ' + this.state.name + ', 年齡: ' + this.ageInputRef.current.value);
    event.preventDefault();
  };

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          名稱:
          <input type="text" value={this.state.name} onChange={this.handleNameChange} />
        </label>
        <br />
        <label>
          年齡:
          <input type="number" ref={this.ageInputRef} />
        </label>
        <br />
        <button type="submit">提交</button>
      </form>
    );
  }
}

export default MixedForm;

在這個範例中:

  • 名稱 (name) 是受控元件,由 state 控制。
  • 年齡 (age) 是非受控元件,通過 ref 來獲取值。

5. 何時選擇受控或非受控元件?

  • 如果你需要即時驗證、動態更新或對表單數據進行複雜處理,受控元件更合適,因為它能更好地掌控數據流。
  • 如果表單較為簡單且不需要頻繁操作,可以考慮使用非受控元件,這樣可以減少不必要的狀態管理代碼。

總結

  • 受控元件 通過 state 完全控制表單元素的值,適合需要即時處理或驗證的場景。
  • 非受控元件 依賴於 DOM 來管理其狀態,適合簡單或低頻率更新的場景。
  • 選擇使用受控或非受控元件取決於具體的應用需求。如果需要對表單進行複雜處理或驗證,受控元件會更靈活。如果表單較為簡單且不需要太多的處理,非受控元件則更輕便。
本文章以 CC BY 4.0 授權