七進七出React高階組件

爲何要使用高階組件?

想一想之前用原生和jQuery的項目,上千行的code映入眼簾,瞬間有種昏死過去的衝動。代碼難以維護,改一個bug可能出現N個bug,真的是很痛苦。因而乎組件化成爲了當前前端開發的主流技術。angular、vue和react很好的幫咱們實現了組件化。前端

可是咱們經常也會遇到一種狀況,就是兩個組件每每有不少的重複代碼(多是相同的屬性,也多是相同的方法)。例如,在登陸和註冊組件中,都會有用戶名和密碼,以及對他們的校驗規則。爲了提升代碼的複用性和可維護性,React高階函數應運而生。vue

React以前對此的解決方案是mixin,但這形成和不少沒必要要的問題,後來就被廢棄掉了。使用過vue的同窗,不知道有沒有使用過mixin,react高階函數的做用和它是同樣的。react

高階組件究竟是個什麼東西?

高階組件實際上是一個函數,它並非一個組件,咱們須要向它傳遞一些參數(想要操做的組件、屬性)。這麼提及來它其實一點也不高階,它的做用就是存儲一些公共的屬性和方法。chrome

咱們常常幾我的吃過一個鍋底的那種火鍋,鍋底裏有火鍋底料和各類佐料,咱們把肉和蔬菜等放進去涮一下,就能夠美美的飽餐一頓。高階函數在react編程中扮演的角色就是火鍋鍋底的角色,它有公用的方法和屬性,而各類組件就是肉和蔬菜。若是是一我的一個鍋的火鍋就像沒有通過封裝的code,代碼量重複且維護困難。編程

如何實現高階函數?

咱們先來看一段可使用高階函數的代碼:react-router

這裏有一個Second組件,它負責展現用戶名username函數

export class Second extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            username: ''
        }
    }
    componentWillMount() {
        let username = localStorage.getItem('username');
        this.setState({
            username: username
        });
    }
    render() {
        return(
            <div>
                <legend>Second Page</legend>
                <h2>Hi {this.state.username}</h2>
            </div>
        )
    }
}

下面是一個Third組件,它也負責展現用戶名組件化

export class Third extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            username: ''
        }
    }
    componentWillMount() {
        let username = localStorage.getItem('username');
        this.setState({
            username: username
        });
    }
    render() {
        return(
            <div>
                <legend>Third Page</legend>
                <h2>Hi {this.state.username}</h2>
                <p>我今年18歲了</p>
            </div>
        )
    }
}

咱們看到這兩個組件除了名稱之外,其他大量的代碼是同樣的,咱們徹底能夠考慮將它們通用的代碼提取出來。下面就是高階組件出場的時候了。this

高階組件能夠寫成這樣spa

export const HighOrderComponent = (WrapComponent, title) => {
    return class HOC extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                username: ''
            }
        }
        componentWillMount() {
            let username = localStorage.getItem('username');
            this.setState({
                username: username
            });
        }
        static displayName = `HOC(${getDisplayName(WrapComponent)})`;
        render() {
            return(
                <div>
                    <legend>{title}</legend>
                    <WrapComponent username={this.state.username}></WrapComponent>
                </div>
            )
        }
    }
}
  • WrapComponent 是咱們要操做的組件
  • title 是它們的標題參數
  • username 就是咱們經常使用的props,它負責向組件傳遞值,咱們下面還會提到

使用高階組件以後咱們要對Second和Third組件進行修改,修改以下

class Second extends React.Component {
    render() {
        return(
            <div>
                <h2>Hi {this.props.username}</h2>
                <h3>曉不曉得哪裏好耍</h3>
            </div>
        )
    }
}
export const HighOrderSecond = HighOrderComponent(Second, 'Second Page');
class Third extends React.Component {

    render() {
        return(
            <div>
                <h2>Hi {this.props.username}</h2>
            </div>
        )
    }
}
export const HighOrderThird = HighOrderComponent(Third, 'Third Page');

不少同窗可能會問,export出去的常量是幹什麼用的,它就是高階組件對組件進行封裝以後的一個全新的組件,是二者的結合。到此,咱們在其它頁面引用組件就再也不是引用Second和Third組件了,要引用的就是HighOrderSecond和HighOrderThird了。

細心的同窗可能會發現一些不一樣的地方,對於Second和Third的公共legend提取出去了,但並無將h2對應得標題提取出去,這裏只是想給你們說一下,在對組件使用高階組件包裹以後,高階組件就變成了組件的父組件,它的state能夠經過props的方式向子組件傳遞,username就是這樣。咱們在chrome的react插件中能夠觀察到這一點

HOC已經將Second組件包裹起來,成爲了它的父組件,它上面的match和location是我使用了react-router的緣故,咱們能夠不用去管它。它的state——username做爲props傳給了Second

今天給你們簡單的介紹了React高階組件的一些知識,後續還會再深刻的挖掘React高階組件的知識和你們分享,但願對你們有幫助。文章轉自我的掘金帳號,轉載請註明出處,謝謝

相關文章
相關標籤/搜索