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

翻譯:劉小夕

原文鏈接:https://dmitripavlutin.com/7-...

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

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

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

組合

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

組合(composition)是一種通過將各組件聯合在一起以創建更大組件的方式。組合是 React 的核心。

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

clipboard.png

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

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')); 

應用程序演示了組合如何構建應用程序。這種組織這樣組織代碼即富於表現力又便於理解。

React 組件的組合是自然而然的。這個庫使用了一個聲明範式,從而不會抑制組合式的表現力。

<Application><Header><Sidebar> <Content><Footer> 組成. <Sidebar> 有一個 <Menu> 組件, <Content> 有一個 <Article> 組件.

那麼組合與單一責任以及封裝有什麼聯繫呢?讓我們一起看看:

單一責任原則描述瞭如何將需求拆分爲組件,封裝描述瞭如何組織這些組件,組合描述瞭如何將整個系統粘合在一起。

組合的好處

單一責任

組合的一個重要方面在於能夠從特定的小組件組成複雜組件的能力。這種分而治之的方式幫助了被組合而成的複雜組件也能符合 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章