淺談React受控與非受控組件


背景

React內部分別使用了props, state來區分組件的屬性和狀態。props用來定義組件外部傳進來的屬性, 屬於那種經過外部定義之后, 組件內部就無法改變。而state維持組件內部的狀態更新和變化, 組件渲染出來后響應用戶的一些操作,更新組件的一些狀態。如果組件內部狀態不需要更新,即沒有調用過this.setState, 全部通過props來渲染也是沒問題的, 不過這種情況不常見。本文所介紹的內容就是通過props和state的定義來談談React的受控組件和非受控組件。

非受控組件

顧名思義, 非受控組件即組件的狀態改變不受控制.接來下我們以一個簡單input組件代碼來描述。

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,會發現輸入框的值無法改變。

受控組件

上面提到過,既然通過設置input的value屬性, 無法改變輸入框值,那么我們把它和state結合在一起,再綁定onChange事件,實時更新value值就行了。

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框只能輸入數字

this.setState({
    value: e.target.value.replace(/\D/g, '')
})

現在我們應該完全明白form表單中受控組件和非受控組件的關系。受控組件采取的理念類似於redux的單項數據流理念,即value值是在調用者上更新的。
那么問題來了。。。

最后的思考

現在我們要實現一個簡單的input的number類型組件,后面緊跟一個+的button按鈕,將輸入框內的數字每次加一。所以此處只能按照受控組件的理念來寫

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組件的代碼如下

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,歡迎指正交流。


免責聲明!

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



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