受控組件和非受控組件


受控組件和非受控組件

React的受控組件與非受控組件的概念是相對於表單而言的,在React中表單元素通常會持有一下內部的state,因此它的工作方式與其他HTML元素不一樣,而獲取表單元素內部state的實現方式的不同,就產生了受控組件和非受控組件。

受控組件

HTML的表單元素中,它們通常自己維護一套state,並隨着用戶的輸入自己進行UI上的更新,這種行為是不被我們程序所管控的,而如果將React里的state屬性和表單元素的值建立依賴關系,再通過onChange事件與setState()結合更新state屬性,就能達到控制用戶輸入過程中表單發生的操作,React以這種方式控制取值的表單輸入元素就叫做受控組件。
React中定義了一個input輸入框的話,它並沒有類似於Vuev-model的這種雙向綁定功能,也就是說我們並沒有一個指令能夠將數據和輸入框結合起來,用戶在輸入框中輸入內容,然后數據同步更新。

class Input extends React.Component {
  render () {
    return <input name="username" />
  }
}

用戶在界面上的輸入框輸入內容時,它是自己維護了一個state,這個state並不是我們平常看見的this.state,而是每個表單元素上抽象的state,這樣的話就能根據用戶的輸入自己進行UI上的更新,如果我們想要控制輸入框的內容,而輸入框的內容取決的是input中的value屬性,那么我們可以在this.state中定義一個名為username的屬性,並將input上的value指定為這個屬性。

class Input extends React.Component {
  constructor (props) {
    super(props);
    this.state = { username: "1" };
  }
  render () {
    return <input name="username" value={this.state.username} />
  }
}

但是這時候你會發現input的內容是只讀的,因為value會被我們的this.state.username所控制,當用戶輸入新的內容時,this.state.username並不會自動更新,這樣的話input內的內容也就不會變了,此時控制台通常會拋出一個Warning

Warning: You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`.

您為表單字段提供了一個沒有onChange處理程序的value屬性,這將呈現只讀字段,如果字段應該是可變的,請使用defaultValue,否則請設置onChangereadOnly
這段Warning其實給出了對於這個問題的解決方案,我們只需要對組件的onChange事件來監聽輸入內容的改變並使用setState更新this.state.username即可,如此我們在當前組件中能夠控制這個表單元素的值,這就是受控組件。

class Input extends React.Component {
  constructor (props) {
    super(props);
    this.state = { username: "1" };
  }
  render () {
    return (
      <>
        <input name="username" value={this.state.username} 
          onChange={e => this.setState({username: e.target.value})} 
        />
        <button onClick={() => console.log(this.state.username)} >Log</button>
      </>
    )
  }
}

此外需要注意的是,如果是講此組件作為一個共用的組件用以調用的話,是有弊端的,盡管此時Input組件本身是一個受控組件,但與之相對的調用方失去了更改Input組件值的控制權,所以對調用方而言,Input組件是一個非受控組件,以非受控組件的使用方式去調用受控組件是一種反模式,下邊的例子都是屬於Hooks的寫法。

// 組件提供方
function Input({ defaultValue }) {
  const [value, setValue] = React.useState(defaultValue)
  return <input value={value} onChange={e => setValue(e.target.value)} />
}

// 調用方
function UseInput() {
  return <Input defaultValue={1} />
}

如果要對於組件提供方還是調用方Input組件都為受控組件,只需要提供方讓出控制權即可。

// 組件提供方
function Input({ value, onChange }) {
  return <input value={value} onChange={onChange} />
}

// 調用方
function UseInput() {
  const [value, setValue] = React.useState(1);
  return <Input value={value} onChange={e => setValue(e.target.value)} />
}

非受控組件

如果表單元素並不經過state,而是通過ref修改或者直接操作DOM,那么它的數據無法通過state控制,這就是非受控組件。

class Input extends React.Component {
  constructor (props) {
    super(props);
    this.input = React.createRef();
  }
  render () {
    return (
      <>
        <input name="username" ref={this.input} />
        <button onClick={() => console.log(this.input.current.value)} >Log</button>
      </>
    )
  }
}

總結

受控組件

  • 每當表單的狀態發生變化時,都會被寫入到組件的state中。
  • 在受控組件中,組件渲染出的狀態與它的valuechecked prop相對應。
  • react受控組件更新state的流程:
    • 通過在初始state中設置表單的默認值。
    • 每當表單的值發生變化時,調用onChange事件處理器。
    • 事件處理器通過合成對象event拿到改變后的狀態,並更新應用的state
    • SetState觸發視圖的重新渲染,完成表單組件值的更新。

非受控組件

  • 如果一個表單組件沒有value prop就可以稱為非受控組件。
  • 非受控組件是一種反模式,它的值不受組件自身的stateprops控制。
  • 通常需要為其添加ref prop來訪問渲染后的底層DOM元素。
  • 可通過添加defaultValue指定value值。

每日一題

https://github.com/WindrunnerMax/EveryDay

參考

https://muyunyun.cn/posts/8bdf2cdf/
https://zhuanlan.zhihu.com/p/89223413
https://juejin.cn/post/6844904154133954568
https://juejin.cn/post/6858276396968951822
https://segmentfault.com/a/1190000022925043
https://segmentfault.com/a/1190000012458996
https://zh-hans.reactjs.org/docs/glossary.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM