翻譯:劉小夕原文連接:https://dmitripavlutin.com/7-...javascript
原文的篇幅很是長,不過內容太過於吸引我,仍是忍不住要翻譯出來。此篇文章對編寫可重用和可維護的React組件很是有幫助。但由於篇幅實在太長,我對文章進行了分割,本篇文章重點闡述 組合和複用。因水平有限,文中部分翻譯可能不夠準確,若是你有更好的想法,歡迎在評論區指出。html
更多文章可戳: https://github.com/YvetteLau/...前端
———————————————我是一條分割線————————————————java
一個組合式組件是由更小的特定組件組合而成的。
組合(composition)是一種經過將各組件聯合在一塊兒以建立更大組件的方式。組合是 React 的核心。react
幸運的是,組合易於理解。把一組小的片斷,聯合起來,建立一個更大個兒。git
讓咱們來看一個常見的前端應用組合模式。應用由頭部的 header
、底部的 footer
、左側的 sidebar
,還有中部的有效內容聯合而成:github
<div id="root"></div>
function Application({ children }) { return ( <div className="application box"> <Label>Application</Label> {children} </div> ); } function Header() { return ( <div className="header box"> <Label>Header</Label> </div> ) } function Footer() { return ( <div className="header box"> <Label>Footer</Label> </div> ) } function Sidebar({ children }) { return ( <div className="sidebar box"> <Label>Sidebar</Label> {children} </div> ); } function Content({ children }) { return ( <div className="content box"> <Label>Content</Label> {children} </div> ) } function Menu() { return ( <div className="menu box"> <Label>Menu</Label> <div className="description"> <div className="text shorter" /> <div className="text" /> <div className="text shorter" /> <div className="text shorter" /> </div> </div> ); } function Article() { return ( <div className="article box"> <Label>Article</Label> <div className="description"> <div className="text shorter" /> <div className="text longer" /> <div className="text shorter" /> <div className="text" /> <div className="text shorter" /> <div className="text" /> <div className="text" /> <div className="text shorter" /> <div className="text shorter" /> <div className="text" /> <div className="text" /> <div className="text shorter" /> <div className="text shorter" /> <div className="text longer" /> <div className="text shorter" /> <div className="longer" /> <div className="text shorter" /> <div className="text" /> <div className="text" /> <div className="text shorter" /> <div className="text shorter" /> <div className="text" /> </div> </div> ); } function Label({ children }) { return <div className="label"><{children}></div> } const app = ( <Application> <Header /> <Sidebar> <Menu /> </Sidebar> <Content> <Article /> </Content> <Footer /> </Application> ); ReactDOM.render(app, document.getElementById('root'));
應用程序演示了組合如何構建應用程序。這種組織這樣組織代碼即富於表現力又便於理解。redux
React 組件的組合是天然而然的。這個庫使用了一個聲明範式,從而不會抑制組合式的表現力。react-router
<Application>
由 <Header>
、 <Sidebar>
<Content>
和 <Footer>
組成. <Sidebar>
有一個 <Menu>
組件, <Content>
有一個 <Article>
組件.app
那麼組合與單一責任以及封裝有什麼聯繫呢?讓咱們一塊兒看看:
單一責任原則描述瞭如何將需求拆分爲組件, 封裝描述瞭如何組織這些組件,組合描述瞭如何將整個系統粘合在一塊兒。
組合的一個重要方面在於可以從特定的小組件組成複雜組件的能力。這種分而治之的方式幫助了被組合而成的複雜組件也能符合 SRP 原則。
回顧以前的代碼片斷,<Application>
負責渲染 header
、footer
、sidebar
和主體區域。
將此職責分爲四個子職責是有意義的,每一個子職責由專門的組件實現,分別是<header>
、<sidebar>
、<content>
和 <footer>
。隨後,這些組件被粘合在 <Application>
。
如今來看看組合的好處:經過子組件分別實現單一職責的方式,使 <Application>
組件也符合單一責任原則。
組合有可重用的有點,使用組合的組件能夠重用公共邏輯,
例如,組件 <Composed1>
和 <Composed2>
有一些公共代碼:
const instance1 = ( <Composed1> /* Specific to Composed1 code... */ /* Common code... */ </Composed1> ); const instance2 = ( <Composed2> /* Common code... */ /* Specific to Composed2 code... */ </Composed2> );
代碼複製是一個很差的實踐(例如更改 Composed1
的代碼時,也須要去更改Composed2
中的代碼),那麼如何使組件重用公共代碼?
首先,將共同代碼封裝到一個新組件中,如 <Common>
中,而後
首先,在新組件中封裝公共代碼。其次,<Composed1>
和 <Composed2>
應該使用組合的方式來包含 <Common>
組件,以免代碼重複,以下:
const instance1 = ( <Composed1> <Piece1 /> <Common /> </Composed1> ); const instance2 = ( <Composed2> <Common /> <Piece2 /> </Composed2> );
可重用的組件符合不重複本身(Don't repeat yourself
)的原則。這種作法能夠節省你的精力和時間,而且在後期,有利於代碼維護。
在 react
中,一個組合式的組件經過給子組件傳遞 props
的方式,來控制其子組件。這就帶來了靈活性的好處。
例如,有一個組件,它須要根據用戶的設備顯示信息,使用組合能夠靈活地實現這個需求:
function ByDevice({ children: { mobile, other } }) { return Utils.isMobile() ? mobile : other; } <ByDevice>{{ mobile: <div>Mobile detected!</div>, other: <div>Not a mobile device</div> }}</ByDevice>
<ByDevice>
組合組件,對於移動設備,顯示: Mobile detected!
; 對於非移動設備,顯示 Not a mobile device"
。
用戶界面可組合的層次結構,所以,組件的組合是一種構建用戶界面的有效的方式。
注:DRY
原則理論上來講是沒有問題的,但在實際應用是切忌死搬教條。它只能起指導做用,沒有量化標準,不然的話理論上一個程序每一行代碼都只能出現一次才行,這是很是荒謬的,其它的原則也是同樣,起到的也只是指導性的做用。
可重用的組件,一次編寫屢次使用。
想象一下,若是軟件開發老是重複造輪子。那麼當你編寫代碼時,不能使用任何已有庫或工具。甚至在同一個應用中你都不能使用已經編寫過的代碼。在這種環境中,是否有可能在合理的時間內編寫出一個應用呢?絕無可能。
此時應該到認識重用的重要性,使用已有的庫或代碼,而不是重複造輪子。
根據「不要重複本身」(DRY
)原則,每一條知識都必須在系統中具備單一,明確,權威的表示。這個原則建議避免重複。
代碼重複增長了複雜性和維護工做,但沒有增長顯著的價值。邏輯更新迫使您修改應用程序中的全部重複代碼。
重複問題能夠用可複用組件來解決。一次編寫,屢次使用。
可是,複用並不是毫無成本。只有一個組件符合單一責任原則而且具備合理的封裝時,它是可複用的。
符合單一職責原則是必須的:
複用一個組件實際上就意味着複用其職責
只有一個職責的組件是最容易複用的。
可是,當一個組件錯誤地具備多個職責時,它的複用會增長大量的開銷。你只想複用一個職責實現,但也會獲得沒必要要的職責實現。好比,你只是想要一個香蕉,可是在你獲得一個香蕉的同時,不得不被迫接受全部的叢林。
合理封裝的組件。隱藏了內部實現,而且有明確的 props
,使得組件可使用與多種須要複用的場合。
某個工做日,你剛剛收到了爲應用增長新特性的任務,在撩起袖子狂敲代碼以前,先稍等幾分鐘。
你要作的工做在很大機率上已經被解決了。因爲 React
很是流行以及其很是棒的開源社區,先搜索一下是否有已存在的解決方案是明智之舉。
查看 brillout/awesome-react-components
,它有一個可複用的組件列表。
優秀的第三方庫有結構性的影響,而且會推廣最佳實踐。以個人經驗而言,最有影響的當屬 react-router
和 redux
。
react-router
使用了聲明式的路由來構建一個單頁應用。使用 <Route>
將 URL
和組件關聯起來。當用戶訪問匹配的 URL
時,路由將渲染相應的組件。
redux
和 react-redux
引入了單向和可預測的應用狀態管理。能夠將異步的和非純的代碼(例如 HTTP
請求)從組件中提取出來,從而符合單一職責原則並建立出 純(pure)組件 或 幾乎純(almost-pure)的組件。
這裏是一份檢查清單能夠肯定第三方庫是否值得使用,:
README.md
文件和詳細的文檔最後謝謝各位小夥伴願意花費寶貴的時間閱讀本文,若是本文給了您一點幫助或者是啓發,請不要吝嗇你的贊和Star,您的確定是我前進的最大動力。https://github.com/YvetteLau/...
推薦關注本人公衆號