淺談React受控與非受控組件

背景

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

相關文章
相關標籤/搜索