展示組件和容器組件的區(qū)別和應(yīng)用

在使用React中尚揣,你是否會出現(xiàn)過一個文件的代碼很多,既存在應(yīng)用數(shù)據(jù)的讀取和處理掖举,又存在數(shù)據(jù)的顯示快骗,而且每個組件還不能復(fù)用。

首先我們來看一個容器組件和展示組件一起的例子吧塔次。

class TodoList extends React.Component{
    constructor(props){
        super(props);
        this.state ={
            todos:[]
        }
        this.fetchData = this.fetchData.bind(this);
    }
    componentDidMount(){
        this.fetchData();
    }
    fetchData(){
        fetch('/api/todos').then(data =>{
            this.setState({
                todos:data
            })
        })
    }
    render(){
        const {todos} = this.state;
        return (<div>
                <ul>
                    {todos.map((item,index)=>{
                        return <li key={item.id}>{item.name}</li>
                    })}
                </ul>
            </div>)
    }
}

大家可以看到這個例子是沒有辦法復(fù)用的方篮,因為數(shù)據(jù)的請求和數(shù)據(jù)的展示都在一個組件進行,要實現(xiàn)組件的復(fù)用励负,我們就需要將展示組件和容器組件分離出來藕溅。

具體代碼如下:

//展示組件
class TodoList extends React.Component{
    constructor(props){
        super(props);
    }
    render(){
        const {todos} = this.props;
        return (<div>
                <ul>
                    {todos.map((item,index)=>{
                        return <li key={item.id}>{item.name}</li>
                    })}
                </ul>
            </div>)
    }

//容器組件
class TodoListContainer extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            todos:[]
        }
        this.fetchData = this.fetchData.bind(this);
    }
    componentDidMount(){
        this.fetchData();
    }
    fetchData(){
        fetch('/api/todos').then(data =>{
            this.setState({
                todos:data
            })
        })
    }
    render(){
        return (<div>
                <TodoList todos={this.state.todos} />    
            </div>)
    }
}

當(dāng)我們把組件分離成容器組件和展示組件這兩類時,你會發(fā)現(xiàn)他們能夠很方便的實現(xiàn)復(fù)用继榆。

展示組件(Presentational Component)

  1. 關(guān)注頁面的展示效果(外觀)
  2. 內(nèi)部可以包含展示組件和容器組件巾表,通常會包含一些自己的DOM標(biāo)記和樣式(style)
  3. 通常允許通過this.props.children方式來包含其他組件。
  4. 對應(yīng)用程序的其他部分沒有依賴關(guān)系略吨,例如Flux操作或store集币。
  5. 不用關(guān)心數(shù)據(jù)是怎么加載和變動的。
  6. 只能通過props的方式接收數(shù)據(jù)和進行回調(diào)(callback)操作翠忠。
  7. 很少擁有自己的狀態(tài)鞠苟,即使有也是用于展示UI狀態(tài)的。
  8. 會被寫成函數(shù)式組件除非該組件需要自己的狀態(tài)秽之,生命周期或者做一些性能優(yōu)化当娱。

Example:
Page,Header,Sidebar,UserInfo,List

容器組件(Container Component)

  1. 關(guān)注應(yīng)用的是如何工作的
  2. 內(nèi)部可以包含容器組件和展示組件考榨,但通常沒有任何自己的DOM標(biāo)記跨细,除了一些包裝divs,并且從不具有任何樣式董虱。
  3. 提供數(shù)據(jù)和行為給其他的展示組件或容器組件扼鞋。
  4. 調(diào)用Flux操作并將它們作為回調(diào)函數(shù)提供給展示組件造成。
  5. 往往是有狀態(tài)的掉盅,因為它們傾向于作為數(shù)據(jù)源
  6. 通常使用高階組件生成挽放,例如React Redux的connect(),Relay的createContainer()或Flux Utils的Container.create()淫半,而不是手工編寫。

Example:
UserPage, FollowersSidebar, StoryContainer, FollowedUserList

優(yōu)點(benifit)

  1. 展示和容器組件更好的分離匣砖,有助于更好的理解應(yīng)用和UI
  2. 重用性高科吭,展示組件可以用于多個不同數(shù)據(jù)源昏滴。
  3. 展示組件就是你的調(diào)色板,可以把他們放到單獨的頁面对人,在不影響應(yīng)用程序的情況下谣殊,讓設(shè)計師調(diào)整UI。
  4. 這迫使您提取諸如側(cè)邊欄牺弄,頁面姻几,上下文菜單等“布局組件”并使用this.props.children,而不是在多個容器組件中復(fù)制相同的標(biāo)記和布局势告。

何時引入容器組件

我建議你從開始創(chuàng)建組件時只使用展示組件蛇捌,到最后會意識到你傳遞了很多props到中間組件,而這些中間組件根本不會用到他們接收到的這些props咱台,僅僅是向下傳遞。而當(dāng)這些子組件需要更多的數(shù)據(jù)時回溺,你需要從新配置這些中間組件春贸。這個時候就需要引入容器組件了遗遵。使用容器組件的方式,您可以將數(shù)據(jù)和行為通過props傳遞給葉子組件瓮恭,而不必麻煩一些不相關(guān)的中間組件雄坪。

這是一個重構(gòu)的過程屯蹦,所以不必在第一次就做對。當(dāng)你嘗試這種模式登澜。在何時應(yīng)抽取為容器組件你將會有一種直觀的感覺阔挠。就像您知道何時抽取函數(shù)一樣

二分法

重要的是你需要明白容器組件和展示組件之間不是技術(shù)上的區(qū)別脑蠕,而是目的上的區(qū)別购撼。

相比之下,這里有幾個相關(guān)的(但不同的)技術(shù)區(qū)別:

  1. 有狀態(tài)【Stateful】和 無狀態(tài)【Stateless】:

容器組件傾向于有狀態(tài)谴仙,展示組件傾向于無狀態(tài)迂求,這不是硬性規(guī)定,因為容器組件和展示組件都可以是有狀態(tài)的晃跺。

  1. 類【Classes】 和 函數(shù)【Functions】:

組件可以被申明成類或函數(shù)揩局,函數(shù)組件定義簡單,但是他缺乏目前僅用于類的一些功能掀虎。雖然函數(shù)組件有很多限制凌盯,但是直到現(xiàn)在還有人使用付枫,是因為函數(shù)組件容易理解,建議在不需要自己的state,lifecycle hooks,或性能優(yōu)化的情況下使用函數(shù)組件驰怎。這些僅適用于類組件阐滩。

//我們將上邊的展示組件改寫成函數(shù)組件可以如下
function TodoList(props){
    return (<div>
              <ul>
                    {props.todos.map((item,index)=>{
                        return <li key={item.id}>{item.name}</li>
                    })}
                </ul>  
        </div>)
}

可能很多人不清楚函數(shù)組件和類組件的區(qū)別,可以去React的官網(wǎng)看一下函數(shù)組件和類組件

  1. 純粹【Pure】 和 不純粹 【Impure】:

純粹:輸入什么就輸出什么县忌,不會再其中做相應(yīng)的變動掂榔。可以被定義為類或函數(shù)芹枷,可以是無狀態(tài)或有狀態(tài)的衅疙,純組件的另一個重要方面是它們不依賴props或state中的深度變動,所以他們的渲染性能可以通過在shouldComponentUpdate()鉤子中進行淺層比較來優(yōu)化鸳慈,當(dāng)前只有類可以定義shouldComponentUpdate()方法饱溢。

不管是展示組件還是容器組件都會有上面的二分特性。在我看來走芋,展示組件往往是沒有狀態(tài)的純函數(shù)绩郎,而容器組件往往是有狀態(tài)的純類,這僅僅個人觀點并非規(guī)則翁逞。

當(dāng)不重要或說很難分清時,不要把分離容器組件和展示組件當(dāng)做教條肋杖,
如果你不確定該組件是容器組件還是展示組件是,就暫時不要分離挖函,寫成展示組件吧状植。

譯文來源:https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市怨喘,隨后出現(xiàn)的幾起案子津畸,更是在濱河造成了極大的恐慌,老刑警劉巖必怜,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肉拓,死亡現(xiàn)場離奇詭異,居然都是意外死亡梳庆,警方通過查閱死者的電腦和手機暖途,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來膏执,“玉大人驻售,你說我怎么就攤上這事「祝” “怎么了芋浮?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長壳快。 經(jīng)常有香客問我纸巷,道長眶痰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任存哲,我火速辦了婚禮七婴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘修肠。我一直安慰自己,他們只是感情好嵌施,可當(dāng)我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布莽鸭。 她就那樣靜靜地躺著吗伤,像睡著了一般足淆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上巧号,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天氮兵,我揣著相機與錄音,去河邊找鬼卜高。 笑死,一個胖子當(dāng)著我的面吹牛掺涛,可吹牛的內(nèi)容都是我干的疼进。 我是一名探鬼主播,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼拣帽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了减拭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤修陡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后魄鸦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體癣朗,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年盾致,在試婚紗的時候發(fā)現(xiàn)自己被綠了荣暮。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡护赊,死狀恐怖砾跃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抽高,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布壁熄,位于F島的核電站碳竟,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏莹桅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一懂拾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧委粉,春花似錦、人聲如沸贾节。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至菩混,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沮峡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工棍弄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留疟游,地道東北人。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓蛮原,卻偏偏與公主長得像,于是被迫代替她去往敵國和親儒陨。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,678評論 2 354