React內部分別使用了props, state來區分組件的屬性和狀態。props用來定義組件外部傳進來的屬性, 屬於那種通過外部定義以後, 組件內部就沒法改變。而state維持組件內部的狀態更新和變化, 組件渲染出來後響應用戶的一些操做,更新組件的一些狀態。若是組件內部狀態不須要更新,即沒有調用過this.setState
, 所有經過props來渲染也是沒問題的, 不過這種狀況不常見。本文所介紹的內容就是經過props和state的定義來談談React的受控組件和非受控組件。react
顧名思義, 非受控組件即組件的狀態改變不受控制.接來下咱們以一個簡單input組件代碼來描述。git
import React, { Component } from 'react'; import ReactDOM from 'react-dom'; class Demo1 extends Component { render() { return ( <input /> ) } } ReactDOM.render(<Demo1/>, document.getElementById('content'))
在這個最簡單的輸入框組件裏,咱們並無干涉input中的value展現,即用戶輸入的內容都會展現在上面。若是咱們經過props給組件設置一個初始默認值,<input defaultValue={this.props.value}/>
defaultValue屬性是React內部實現的一個屬性,目的相似於input的placeholder屬性。
ps: 此處若是使用value代替defaultValue,會發現輸入框的值沒法改變。github
上面提到過,既然經過設置input的value屬性, 沒法改變輸入框值,那麼咱們把它和state結合在一塊兒,再綁定onChange事件,實時更新value值就好了。redux
class Demo1 extends Component { constructor(props) { super(props); this.state = { value: props.value } } handleChange(e) { this.setState({ value: e.target.value }) } render() { return ( <input value={this.state.value} onChange={e => this.handleChange(e)}/> ) } }
這就是最簡單的受控組件模型, 咱們能夠經過在onChange的回調裏控制input要顯示的值,例如咱們設置input框只能輸入數字dom
this.setState({ value: e.target.value.replace(/\D/g, '') })
如今咱們應該徹底明白form表單中受控組件和非受控組件的關係。受控組件採起的理念相似於redux的單項數據流理念,即value值是在調用者上更新的。
那麼問題來了。。。函數
如今咱們要實現一個簡單的input的number類型組件,後面緊跟一個+的button按鈕,將輸入框內的數字每次加一。因此此處只能按照受控組件的理念來寫this
import React, { Component } from 'react'; export default class extends Component { constructor(props) { super(props); this.state = { value: props.value } } handleChange(e) { this.setState({ value: e.target.value.replace(/\D/g, '') }) } plus() { const value = ++this.input.value this.setState({ value, }) } render() { return ( <div> <input value={this.state.value} onChange={e => this.handleChange(e)} ref={ref => this.input = ref} /> <button onClick={() => this.plus()}>+</button> </div> ) } }
此處功能基本實現徹底,可是發現使用此組件以後,面臨了另外一個問題,咱們如何在外部獲取到這個輸入框的值。一種方法是給組件增長個getValue回調的props,每次value值變化都調用一次getValue,即在handleChange和plus函數裏調用,可是存在一個問題是,調用者只能經過getValue被動獲取值,並且value值得改變此時仍是在組件內部自行變化,不符合受控組件原理,也不知足React單向數據流概念。另外一種方法就是將input組件的將要改變的值傳到調用者裏面,由調用者來決定更不更新組件的值,即此時數據由被調用者input組件生成,傳至調用者,調用者判斷知足條件後決定更新,再將數據從新傳入到被調用者裏。而調用者與被調用者彼此之間創建的聯繫方式經過input組件的props和調用者的state。此時input組件的代碼以下code
export default class extends Component { constructor(props) { super(props); this.state = { value: props.value } } componentWillReceiveProps(nextProps) { this.setState({ value: nextProps.value }) } handleChange(e) { this.props.onChange(e.target.value) } plus() { const value = ++this.input.value this.props.onChange(value) } render() { return ( <div> <input value={this.state.value} onChange={e => this.handleChange(e)} ref={ref => this.input = ref} /> <button onClick={() => this.plus()}>+</button> </div> ) } }
代碼中的this.props.onChange就是調用者內部的函數,經過setState來更新input組件的value值。完整代碼已放到github,歡迎指正交流。component