06|React高級組件

其實之所以講到這里是因為,當我們使用React的組件化開發(fā)Web應用的時候,就會遇到這樣的問題,很多組件需要某個功能,但是對應的功能與界面并沒有關(guān)系,無法直接簡單的抽取成為一個組件,但是如果說將類似的功能在不同的組件當中實現(xiàn)的話,就違背了所謂的Don't Your Repeat(DRY原則)

因此我們就需要使用到本節(jié)中講到的內(nèi)容 React高級組件HOC(High Order Component):

其中對應的內(nèi)容如下:

  • 高級組件的概念及其應用
  • 以函數(shù)為子組件的模式

最終的目的就是最大程度的代碼之間的復用,對應的兩者的策略不同,我們也應該針對特定的應用場景進行選擇!

01|什么是HOC(High Order Component)?

簡單來講HOC并不是React提供的某種特定的API,而是一種模式,增強現(xiàn)有組件的功能,對組件進行功能拓展!

  • 高階組件接受一個函數(shù)作為輸入,返回一個新的組件作為結(jié)果 對應的結(jié)果對原有的輸入進行了功能上的增強!

可能我這么說的話,時機上來看還是不是特別的直觀!我們使用代碼來進行簡單的演示:

import React,{Component} from "react";

const removeUserProp = WrappedComponent=>{
    return class WrappingComponent extends Component{
        render(){
            const {user,...otherProps} = this.props;
            return (
                <WrappedComponent {...anotherProp} />   
            );
        }
    } 
}

其中我們使用函數(shù)表達式的方式寫了一個高階函數(shù):

  • 接受一個現(xiàn)有的組件WrappedComponent作為輸入?yún)?shù)
  • 返回一個組件類WrappingComponent,對應的render的結(jié)果就是 剝離了user信息的被包裝的組件!
  • 其中所謂的增強其實就是 屏蔽了不需要的屬性字段

那么通過這個簡單的代碼,我們又能夠想到什么?

  • 如果說別的組件需要使用類似的通能的話或者同樣的功能,就能夠直接使用高階組件進行增強了!

那么對應的根據(jù)新組件和傳入組件參數(shù)的關(guān)系,高階組件的實現(xiàn)方式可以分為兩大類;

  • 代理的方式實現(xiàn)高階組件
  • 繼承的方式實現(xiàn)高階組件
01|代理方式的高階組件

第一個代碼示例其實就是所謂的代理的方式的高階組件,返回的組件直接繼承React.Component類

  • 新組件扮演的角色就是:傳入?yún)?shù)的代理
    • 新建的render函數(shù)中把被包裹的組件渲染出來
    • 高階組件做的工作通常是額外的功能增強,除此之外的工作都交給被包裹的組件
    • 如果說,高階組件所做的功能除了render之外的聲明函數(shù)都不涉及的話,也不需要維護自身的狀態(tài)的話,就可以以函數(shù)組件的方式返回!
const removeUserProp = WrappedComponent=>{
    return function WrappingComponent(props){
        const {user,...otherProps} = props;
        return <WrappedComponent {...otherProps} />
    }
}

這樣依賴對應的邏輯更加的清晰,但是這種所謂的函數(shù)組件的功能是非常有限的,因此我們主要介紹class組件的方式:

代理方式的高階組件可以應用在下列場景當中:

  • 操作prop
  • 訪問ref
  • 抽取狀態(tài)
  • 包裝組件
  1. 操作prop

代理類型高階組件返回的組件(增強的組件),渲染的過程是由新組件的render函數(shù)所控制的!

那么也就是說,被包裹的組件如何使用是由render所決定的! 可以看成是一個代理

render函數(shù)中,新組件的this.props包含所有新組建所接收到的屬性,最簡單的方式就將是接收到的所有屬性{this.props}原封不動的傳遞給被包裹的組件 因為是做功能方面的增強,我們一般都是 增刪改props的方式傳遞給被包裹的組件!

import React,{Component} from "react";
const appendProps = (WrappedComponent,newProps)=>{
    return class WrappingComponent extends Component{
        render(){
            return <WrappedComponent {...this.props} {...newProps}/>
        };
    }
}

通過以上代碼就很好的詮釋了增強功能,并且方便給不同的組件添加不同的屬性!

  1. 訪問ref(reference)

訪問ref并不是React所推薦的做法,但是是可以使用HOC高階組件實現(xiàn)這種功能

import React,{Component} from "react";
const refHoc = WrappedComponent=>{
    return class WrappingComponoent extends Component{
        constructor(){
            super(...arguments);
            this.linkRef = this.linkRef.bind(this);
        }
        linkRef(wrappedInstance){
            this._root = wrappedInstance;
        }
        render(){
            const props = {...this.props,ref:this.linkRef};
            return <WrappedComponent {...props} />
        }
    }
}

以上代碼在linkRef被調(diào)用的時候,就得到了被包裹組件(WrappedComponent)的DOM實例,被保存在了新組件的_root屬性中!

但是實際上用的還是比較少!

  1. 抽取狀態(tài)

其實對應的我們在使用react的時候,react-redux中的connect函數(shù)執(zhí)行完畢返回的函數(shù)是作為高階組件的!

其中我們可以通過 傻瓜組件容器組件 進行理解:

  • 傻瓜組件:無狀態(tài)的組件,負責視圖的渲染
  • 容器組件:負責將狀態(tài)傳遞給傻瓜組件,不負責視圖

傻瓜和容器就是妥妥的抽取狀態(tài),我們通過代碼,簡單理解一下connect高階組件

import React,{Component} from "react";
const doNothing = ()=>({});
const connect = (mapStateToProps=doNothing,mapDispatchToProps=doNothing)=>{
    return function(WrappedComponent){  
        class HocComponent extends Component{
            //lifeCycle fucntion
        }   
        HocComponent.contextTypes = {
            store:React.PropTypes.object
        }
        return HocComponent;
    }
}

和react-redux中的connect方法一樣,我們定義的connect方法接收兩個參數(shù),分別是mapStateToPropsmapDispatchToProps.返回的組件類預期能夠訪問一個叫做store的context的值! 對應的context的值由Provider提供! 對應的我們通過this.context.store進行訪問Provider提供的store實例,對應的實現(xiàn)類似的功能的話,HocComponent組件需要一系列的成員函數(shù)來維持內(nèi)部狀態(tài)和store同步,對應的代碼如下所示:

import React,{Component} from "react";
import {PropTypes} from "prop-types";
class HocComponent extends Component{
    constructor(){
        super(...arguments);
        this.onChange = this.onChange.bind(this);
        this.stroe = {};
    }
    componentDidMount(){
        this.context.store.subscribe(this.onChange);
    }
    componentWillUnmount(){
        this.context.store.unsubscribe(this.onChange);
    }
    onChange(){
        this.setState({});
    }
}

通過借助store的subscribe和unsubscribe函數(shù),HocComponent保證了每當Redux的Store上狀態(tài)發(fā)生變化的時候,都會驅(qū)動組件的更新!

雖然誰應該返回一個有狀態(tài)的組件,但是真正的組件是存在于Redux上的Store上面的,組件內(nèi)的狀態(tài)是什么其實對應的并不重要,使用組件狀態(tài)唯一原因是通過this.setState對狀態(tài)進行更新的過程!

對應的當Redux上面的Store發(fā)生了變化的時候,就可以通過this.setState重設組件狀態(tài),驅(qū)動組件更新的過程!

對應的HocComponent的render函數(shù)如下所示:

render(){
    const store = this.context.store;
    const newProps = {
        ...this.props,
        ...mapStateToProps(store.getState()),
        ...mapDispatchToProps(store.dispatch);
    }
    return <WrappedComponent {...newProps}/>;
}

render中的邏輯類似于"操縱Props"的方式,渲染工作完全交給了WrappedComponent,但是控制住了WrappedComponent的props,該組件能夠渲染什么完全取決于props!

以上的代碼,通過store.getState和store.dispatch可以傳遞給WrappedComponent組件對應的狀態(tài)和dispatch方法!

最終通過調(diào)用connect(mapStateToProps,mapDispatchToProps)(WrappedComponent)里面?zhèn)魅氲慕M件進行了功能增強!

  1. 繼承方式的高階組件

繼承方式的高階組件采用繼承關(guān)系關(guān)聯(lián)作為參數(shù)的組件和返回的組件!如果說傳入的參數(shù)為WrappedComponent那么對應的返回的組件則直接繼承WrappedComponent

對應的我們可以使用這種方式重新實現(xiàn)一遍之前介紹的高級組件的代碼演示示例:

const removeUserProps = WrappedComponent=>{
    return class NewComponent extends WrappedComponent{
        render(){
            const {user,...otherProps} = this.props;
            this.props = otherProps;
            return super.render();
        }
    }
}

對應的代理和繼承最大的區(qū)別就在于,使用被包裹組件的方式

  • 在代理方式下: <WrappedComponent {...otherProps} />
  • 在繼承的方式下: return super.render() 因為我們創(chuàng)造的組件繼承WrappedComponent因此直接調(diào)用父類的渲染函數(shù)即可!

代理方式下產(chǎn)生的新組件和參數(shù)組件是兩個不同的組件,一次渲染兩個組件都需要經(jīng)歷各自的生命周期!

繼承方式下兩者合而為一!只有一個生命周期!

但是以上的代碼修改this.props,對應的做法不太妥當,實際上這樣處理的話不太合適,繼承方式的高階組件可以應用與下列場景:

  • 操作Porps
  • 操作生命周期函數(shù)
  1. 操作Props

集成方式的高階組件對應的也能夠操作Props,除了上面不安全的直接修改this.props的方法,還能夠利用React.cloneElement讓組件重新繪制!

const modifyPropsHOC = WrappedComponent=>{
    return class newComponent extends WrappedComponent{
        render(){
            const elements = super.render();
            const newStyle = {
                color:(elements && elements.type === div) ? "red" : "blue"
            }
            const newProps = {...this.props,style:newStyle};
            return React.cloneElement(elements,newProps,elements.props.children);
        }
    }
}
React.cloneElement(
  element,
  [props],
  [...children]
)

element 元素為樣板克隆并返回新的 React 元素。返回元素的 props 是將新的 props 與原始元素的 props 淺層合并后的結(jié)果睡腿。新的子元素將取代現(xiàn)有的子元素假褪,而來自原始元素的 keyref 將被保留贝或。

以上的代碼添加了一個新的屬性,樣式,如果說元素存在并且對應的頂層元素類型為div的話,那么就設置color顏色為紅色否則為藍色!

最后將本身所存在的props和心得prop屬性合并在一起! 最后通過React.cloneElement讓產(chǎn)生新組件重新渲染一遍!

  1. 操作生命周期函數(shù)

因為繼承方式的高階函數(shù)返回的新組件繼承了參數(shù)組件,因此可以重新定義任何一個React組件的生命周期函數(shù),對應的這是繼承方式高階函數(shù)的特用的場景,則代理的方式無法修改傳入組件的生命周期函數(shù)

如果說參數(shù)組件只有在用戶登錄的時候才能夠渲染對應的界面的時候,那么對應的代碼則如下所示:

const OnlyForLoggedInHOC = WrappedComponent=>{
    return class NewComponent extends WrappedComponent{
        render(){
            if(this.props.loggedIn){
                return super.render();
            }else{
                return null;
            }
        }
    }   
}

其中還可以通過shouldComponentUpdate函數(shù),只要prop中的useCache不為邏輯false就不做重新渲染

const cacheHOC = WrappedComponent=>{
    return class newComponent extends WrappedComponent{
        shouldComponentUpdate(nextProps,nextState){
            return !nextProps.useCache;
        }
    }
}

其實由此便可以看出,代理和繼承的兩種方式,各方面看來代理還是要優(yōu)于繼承方式!

優(yōu)先考慮組合,之后再考慮繼承

03|高階組件的顯示名

其實使用了所謂的高階組件都會產(chǎn)生一個新的組件,使用該組件就丟失掉了參數(shù)組件的 顯示名,因此往往需要給告誡組件重新定義一個 顯示名 不然的話,在我們debug或者說查看日志的時候組件名的顯示就會非常的莫名其妙!

如何給組件添加顯示名?

  • 高階組件類的displayName添加一個字符串類型的值

如果說我們需要在react-redux中的connect返回的作為高階函數(shù),高階組件的名字包含Connect,同時包含參數(shù)組件WrappedComponent的名字,因此需要這么設置!

const getDisplayName = WrappedComponent=>{
    return WrappedComponent.displayName || WrappedComponent.name || "Component";
}
HOCComponent.displayName = `Connect(${getDisplayName(WrappedComponent)})`;
04|曾經(jīng)的Mixin

除了上面所說到的高階組件,其實React中還有一種進行代碼復用的方式,就叫做Mixin,但是我們并不推薦使用它!

const shouldUpdateMixin = {
    shouldComponentUpdate(){
        reurn !this.props.useCache;
    }
}

但是它存在對應的局限性,Mixin只能夠在用React.clearClass的語法創(chuàng)建的組建才能夠使用,如果說ES6的class語法則不適用

const SampleComponent = React.createClass({
    mixins:[shouldUpdateMixin],
    render(){
        //render view
    }
})

使用React.createClass的方式創(chuàng)建的SampleComponent的組件,因為有Mixins字段,成員方法中就混入了shouldUpdateMixin這個對象里面的方法!

那么為什么不推薦使用Mixin呢?

  • 過于靈活
  • 作為設計原則,我們應該盡量將state從組件中抽離出來,mixin則鼓勵在React組件中添加狀態(tài)
  • ES6中的Class語法不支持Mixin,并且同時被官方廢棄了!

02|以函數(shù)作為子組件

高階組件并不是作為提高React組件代碼重用的唯一方法,高階組件通過拓展原有組件的功能的主要方法是通過對Props的控制(增加/減少/修改Props)進行的!

代理方式的高階組件,返回的組件和輸入的組件說到底是兩個組件(原有組件和功能"增強"組件)對應的父子關(guān)系,對應的組件通信方式是通過props來進行通信的!

但是對應的高階組件也有缺點,就是對原組件的Props有了固化的要求,也就是說,能不能把一個高階組件作用于某個組件X,先看一下這個組件X是不是能夠接受高階組件傳過來的props,如果說組件X并不能夠支持這些props的話,或者說對這些props的命名有所不同的話,是不能夠引用這個高階組件的!

假設有一個高階組件addUserProp,讀取對應的loggedinUser,把這個數(shù)據(jù)作為名為user的prop傳遞給參數(shù)組件

import React,{Component} from "react";
const addUserProp = WrappedComponent=>{
    return class WrappingComponent extends Component{
        render(){
            const newProps = {user:loggedinUser};
            return <WrappedComponent {...this.props} {...newProps} />;
        }
    }
}

像前文中所說的那樣,那么作為參數(shù)的組件,需要能夠接受名為user的prop,不然對應的高階組件完全沒效果!

但是如果說作為層層傳遞的props,這種高階組件這種要求參數(shù)組件必須和自己有契約的方式,會帶來很多麻煩!

因此為了更好地解決該問題,于是我們就使用 以函數(shù)為子組件的方式,其實就是為了客服高階組件的這種局限而生的!實現(xiàn)代碼重用的不是一個函數(shù)而是一個真正的React組件! 對應的約束其實也是這樣的:

  • 子組件必須是一個函數(shù)
  • 在組件實例的生命周期中,this.props.children引用的就是自組件,render函數(shù)直接會把this.props.children當作函數(shù)來調(diào)用!

接下來我們按照上面的需求重新使用函數(shù)為子組件的方式重新實現(xiàn)一遍:

import React,{Component} from "react";
import {PropTypes} from "prop-types";
const loggedinUser = 'mock user';
class AddUserProp extends Component{
    render(){
        const user = loggedinUser;
        return this.props.children(user);
    }
}
AddUserProp.propTypes = {
    children:PropTypes.func.isRequired
}

以上代碼中與被增強代碼的聯(lián)系就是this.props.children對應的children為函數(shù)類型!在render函數(shù)中調(diào)用this.props.children參數(shù)就是我們傳遞下去的user!

如果說想讓一個組件把user顯示出來,代碼就是這樣的:

<AddUserProp>
    {user=><div>{user}</div>}
</AddUserProp>

如果說我們想將user作為prop傳遞給一個接受user名prop的組件Foo,那么只需要使用另外一個函數(shù)作為AddUserProp的子組件就行了:

<AddUserProp>
    {user=><Foo user={user} />}
</AddUserProp>

03|一個倒計時的高階組件

我們利用以函數(shù)為子組件的模式構(gòu)建一個復雜一點的CountDown實現(xiàn)倒計時的通用功能:

  1. 初始化組件
import React,{Component} from "react";
class CountDown extends Component{
    constructor(){
        super(...arguments);
        this.state = {count:this.props.startCount};
    }
}

首先需要有一個開始的值,對應的倒計時組件的作用就是持續(xù)驅(qū)動子組件進行更新操作!

當對應的CountDown組件完成掛載之后我們就需要通過setInterval函數(shù)啟動沒秒倒計時更新內(nèi)部的狀態(tài):

componentDidMount(){
    this.intervalHandle = setInterval(()=>{
        const newCount = this.state.count - 1;
        if(newCount>=0){
            this.setState({count:newCount});
        }else{
            window.clearInterval(this.intervalHandle);
        }
    },1000);
}

使用this.intervalHandle 作為間隔調(diào)用的標記,當對應的新的count值小于且不等于0的時候就清除該標記!

其中一定要在componentDidUnmount里面一定要取消并且清理掉intervalHandle,因為CountDown完全可能在沒有倒計時為0的時候被卸載! 因此卸載之前一定需要清除interval的標記:

componentUnmount(){
    if(this.intervalHandle){
       window.clearInterval(this.intervalHandle);
    }
}

對應的渲染部分,和之前講到的同理:

render(){
    reutrn this.props.children(this.state.count);
}

我們還需要對CountDown進行約束:

import PropTypes from "prop-types";
CountDown.propTypes = {
    children:PorpTypes.func.isRequired,
    startCount:PropTypes.number.isRequired
}

如果說有對應的組件需要倒計時的功能,就需要恰當?shù)膶⒑瘮?shù)作為CountDown的子組件即可:

<CountDown startCount={10}>
    {
        count=><div>{count}</div>
    }
</CountDown>

如果說當對應的倒計時為0的時候,就顯示 新年快樂! Happy New Year!

<CountDown startCount={10}>
    {
        count=> <div>{count > 0 ? count : "新年快樂!"}</div>
    }
</CountDown>    

04|性能優(yōu)化問題

函數(shù)作為子組件的方式非常靈活,但是也有其對應的缺點,也就是說,函數(shù)作為子組件的方式難以優(yōu)化!

  • 外層組件的更新過程,都需要執(zhí)行一個函數(shù)獲得子組件的實際渲染效果!
  • 每次渲染都需要執(zhí)行函數(shù),無法使用shouldComponentUpdate進行細粒度的控制,使用高階組件可以直接使用該生命周期函數(shù)避免重新渲染!
  • 如果說定制外層組件的shouldComponentUpdate,每個組件對這個生命周期函數(shù)的定義不同,因此也比較麻煩!

如果說要優(yōu)化的話,對應的CountDown組件也可能會成為別的組件的子組件,因此可以針對CountDown的父組件進行shouldComponentUpdate的設置:

shouldComponentUpdate(nextProps,nextState){
    return nextProps.count !== this.state.count;
}

還有一個問題就是函數(shù)形式的子組件,為了代碼清晰我們使用在jsx中定義的一個箭頭函數(shù)的方式:

<CountDown startCount={10}>
    count=><div>{count}</div>
</CountDown>
  • 用起來非常方便,但是每次都是新的函數(shù),this.porps.children和nextProps.props.children是否有必要性去比較?
    • 雖然說需要比較,但是因為children是函數(shù),因此不能夠使用匿名函數(shù)! 因此該組件內(nèi)部的函數(shù)應該是作為具名函數(shù)存在的!
<CountDown startCount={10}>
    {showCount}
</CountDown>

const showCount = count=>{
    return <div>{count}</div>
}

以函數(shù)為子組件,雖然存在對應的性能問題,但是確實是一個比較不錯的方式,這種模式中代碼的靈活性和性能兩塊需要作為開發(fā)者的我們進行好好地權(quán)衡!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市竞惋,隨后出現(xiàn)的幾起案子吃靠,更是在濱河造成了極大的恐慌塘砸,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钧惧,死亡現(xiàn)場離奇詭異暇韧,居然都是意外死亡,警方通過查閱死者的電腦和手機浓瞪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門懈玻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人乾颁,你說我怎么就攤上這事涂乌。” “怎么了英岭?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵湾盒,是天一觀的道長。 經(jīng)常有香客問我诅妹,道長罚勾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任吭狡,我火速辦了婚禮尖殃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘赵刑。我一直安慰自己分衫,他們只是感情好,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布般此。 她就那樣靜靜地躺著蚪战,像睡著了一般牵现。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上邀桑,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天瞎疼,我揣著相機與錄音,去河邊找鬼壁畸。 笑死贼急,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的捏萍。 我是一名探鬼主播太抓,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼令杈!你這毒婦竟也來了走敌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤逗噩,失蹤者是張志新(化名)和其女友劉穎掉丽,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體异雁,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡捶障,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了纲刀。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片项炼。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖柑蛇,靈堂內(nèi)的尸體忽然破棺而出芥挣,到底是詐尸還是另有隱情,我是刑警寧澤耻台,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布空免,位于F島的核電站,受9級特大地震影響盆耽,放射性物質(zhì)發(fā)生泄漏蹋砚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一摄杂、第九天 我趴在偏房一處隱蔽的房頂上張望坝咐。 院中可真熱鬧,春花似錦析恢、人聲如沸墨坚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽泽篮。三九已至盗尸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間帽撑,已是汗流浹背泼各。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留亏拉,地道東北人扣蜻。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像及塘,于是被迫代替她去往敵國和親莽使。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 前言 學習react已經(jīng)有一段時間了,期間在閱讀官方文檔的基礎上也看了不少文章檬嘀,但感覺對很多東西的理解還是不夠深刻...
    Srtian閱讀 1,647評論 0 7
  • 深入JSX date:20170412筆記原文其實JSX是React.createElement(componen...
    gaoer1938閱讀 8,048評論 2 35
  • React進階之高階組件 前言 本文代碼淺顯易懂槽驶,思想深入實用。此屬于react進階用法鸳兽,如果你還不了解react...
    流動碼文閱讀 1,183評論 0 1
  • 高階組件是react應用中很重要的一部分掂铐,最大的特點就是重用組件邏輯。它并不是由React API定義出來的功能揍异,...
    叫我蘇軾好嗎閱讀 888評論 0 0
  • 探索Vue高階組件 高階組件(HOC)是 React 生態(tài)系統(tǒng)的常用詞匯全陨,React 中代碼復用的主要方式就是使用...
    君惜丶閱讀 963評論 0 2