可靠React組件設計的7個準則之組合和複用

翻譯:劉小夕

原文連接:https://dmitripavlutin.com/7-...javascript

原文的篇幅很是長,不過內容太過於吸引我,仍是忍不住要翻譯出來。此篇文章對編寫可重用和可維護的React組件很是有幫助。但由於篇幅實在太長,我對文章進行了分割,本篇文章重點闡述 組合和複用。因水平有限,文中部分翻譯可能不夠準確,若是你有更好的想法,歡迎在評論區指出。html

更多文章可戳: https://github.com/YvetteLau/...前端

———————————————我是一條分割線————————————————java

組合

一個組合式組件是由更小的特定組件組合而成的。

組合(composition)是一種經過將各組件聯合在一塊兒以建立更大組件的方式。組合是 React 的核心。react

幸運的是,組合易於理解。把一組小的片斷,聯合起來,建立一個更大個兒。git

clipboard.png

讓咱們來看一個常見的前端應用組合模式。應用由頭部的 header、底部的 footer、左側的 sidebar,還有中部的有效內容聯合而成:github

clipboard.png

<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">&lt;{children}&gt;</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> 負責渲染 headerfootersidebar 和主體區域。

將此職責分爲四個子職責是有意義的,每一個子職責由專門的組件實現,分別是<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-routerredux

react-router 使用了聲明式的路由來構建一個單頁應用。使用 <Route>URL 和組件關聯起來。當用戶訪問匹配的 URL 時,路由將渲染相應的組件。

reduxreact-redux 引入了單向和可預測的應用狀態管理。能夠將異步的和非純的代碼(例如 HTTP 請求)從組件中提取出來,從而符合單一職責原則並建立出 純(pure)組件 或 幾乎純(almost-pure)的組件。

這裏是一份檢查清單能夠肯定第三方庫是否值得使用,:
  • 文檔:檢查庫是否具有有意義的 README.md 文件和詳細的文檔
  • 測試過的:可信賴庫的一個顯著特徵就是有高的測試覆蓋率
  • 維護:看看庫做者建立新特性、修改bug及平常維護的頻率

最後謝謝各位小夥伴願意花費寶貴的時間閱讀本文,若是本文給了您一點幫助或者是啓發,請不要吝嗇你的贊和Star,您的確定是我前進的最大動力。https://github.com/YvetteLau/...

推薦關注本人公衆號

clipboard.png

相關文章
相關標籤/搜索