React 導讀(四)

1、前言

React 導讀(三) 中介紹了項目的背景、功能需求、項目結構以及組件的劃分層次,接下來咱們就來看下實際的代碼,這一篇文章會主要分享用到的基礎組件的封裝。javascript

2、基礎組件設計

咱們在設計組件以前原本是有一個流程和過程的,這裏我寫的組件並不會像社區內的組件庫同樣完善或者說必定考慮很完整,可是這樣也會有一個好處,能夠按照本身項目的需求進行定製、擴展以及冗餘的代碼會更少,固然不少時候節約的這點代碼能夠忽略不計(特別是項目業務代碼和庫的代碼比例上升到必定比例事後,因此一切不說場景就說某某庫太大的觀點都是不正確的),由於你們都有按需加載的配置可選。這不是絕對的,不必定說你本身花時間和精力去開發一個這樣的庫就更好,由於隨着項目規模的擴大,組件的種類和需求會愈來愈多,即便是一個不錯的工程師利用技巧保障項目持續迭代,可是人的時間和精力是有限的,更合理的利用現有資源去提升效率纔是最優先考慮的事情。css

我這裏的基礎組件實現了這麼幾個:
Button, Dialog, Input, Loading, Tablehtml

而後分別來介紹一下如何基礎開始封裝和拆合組件。其實基礎組件的設計是很殺腦細胞的,若是要考慮很周全的話,由於要兼顧別人用的爽,也儘量要保留可擴展性,基礎組件若是擴展性太弱,基本等於廢了。其實若是有學習設計模式是能夠相互鏈接的,由於設計模式是成熟的經驗,不是說非要在寫某種邏輯代碼或者作架構設計的時候才能使用,它是可以貫穿在整個軟件週期內的。java

(1) 思考想要如何去組織組件樣式react

首先這裏的組件是 css 和 js 最好可以分開使用的(這裏的分開使用不是指傳統意義的分離,而是保持獨立,可進可退),拿之前 UI 需求來看,就是在同一個結構的 HTML,加上 class 都是可以正常展示的,我這裏的 css 結構是之前用過的,也沒作什麼改動直接拿過來使用的。這種設計思路其實和如今的組件化開發是不衝突的,組件化後還可以使得這種模式更簡單的被實現,由於你只須要考慮組件這個做用域內的樣式。git

(2) Dialog 組件
這裏先拿 Dialog 組件先舉例,這裏我將彈框組件分紅了三部分:DialogHeader, DialogFooter, Dialog 拆分上也沒什麼理由,這是一種簡單直接的拆分,由於不少彈框都具備這麼幾部分:標題、內容、按鈕區域。github

圖片描述

並且不僅是這樣的才叫彈框,彈框如其名:彈出的框,因此都是能夠的,好比下面這種像個 Alert 同樣的彈框:設計模式

圖片描述

我理解的好擴展的組件就像小時候玩的玩具同樣,各部分都是可拆解可組合的,因此彈框的這三部分都須要有必定靈活的地方。來看看代碼,其實蠻簡單的。架構

class Dialog extends React.Component {
    render() {
        const {
            renderHeader,
            renderFooter,
            className,
        } = this.props;

        const header = renderHeader ? renderHeader() : null;
        const footer = renderFooter ? renderFooter() : null;

        const wrapClassName = cx('st-dialog', className);

        return (
            <div className={wrapClassName}>
                <div className="st-dialogContent">
                    {header}
                    {this.props.children}
                    {footer}
                </div>
                <div className="st-dialogMask"></div>
            </div>
        );
    }
}

上面就是一個我這裏 Dialog 的結構,headerfooter採用的是render-props的方式來實現具體的插入,爲何可以採用這種方式其實不難理解,由於在 React 中,一個函數就天然就是一個組件聲明,返回值就能是一個組件實例。我這裏更直接,你要組件返回值,我就給你一個組件...使用上就是這樣:異步

// 這裏結構稍微代碼有點多,就不要揉在一塊兒了,給一個變量存一下更清晰,在 React 中組件的使用是自由的。
const footer = (
    <DialogFooter
        onSubmit={this.handleSubmit}
        onClose={this.handleClose}
        submitText="添加"
        closeText="關閉" />
);

<Dialog className="employeeAddDialog"
    renderHeader={() => <DialogHeader title="添加成員" />}
    renderFooter={() => footer}>
    <div className="addDialog">...</div>
</Dialog>

爲何要這樣設計呢?主要仍是由於有時候需求不定,萬一哪天 DialogFooter 組件不是這樣子,我就在外面實現好組件給這個renderFooter就好了,其餘部分就不須要改動,還有就是實現的時候不要吝嗇div這種容器標籤的使用,多一層就多一個權重,少一層就多了一份自由。

如今還有一個問題,就是個人基礎彈框有了,業務彈框各類各樣,這麼簡單的一個封裝根本不靠譜啊...那麼這裏你就將彈框做爲一個流行的渲染組件來使用,可是是否掛載到業務模塊中就使用封裝的一層業務彈框來控制,好比個人業務彈框叫 EmployeeAddDialog,在 render 方法中:

if(!this.props.visible) {
    return null;
}

return (<Dialog />);

經過一個 visibleprops 值來控制是否掛載 Dialog,那麼這樣作就有一個好處,在處理異步彈框的時候,想何時關閉彈框能夠由業務的流程來控制。在業務組件聲明業務彈框的地方就這樣:

<EmployeeAddDialog visible={this.state.visibleAddDialog}
onClose={this.handleCloseAddDialog} />

而後這樣就實現了一個彈框了,靈活性和擴展性都還好,最後還有一個細節就是這個EmployeeAddDialog始終都掛載在業務組件中,業務組件渲染一次這個彈框更新週期也會走一次,因此可以繼承一下PureComponent來簡單避免屢次執行沒必要要代碼:

class EmployeeAddDialog extends React.PureComponent { }

看上去這個彈框組件還算乾淨,不可能啊,業務太複雜也不會太乾淨,那麼髒的東西去哪兒了呢?我這裏有 2 個比較髒的地方:

(1) Footer,由於有按鈕,每一個需求的按鈕是不同的;
(2) 彈框的內容,這裏就更是千奇百怪,每一個產品經理的腦洞都不同。

我這裏應對上 Footer 有必定的定製又有簡單的開關,好比我就支持2個按鈕:提交類、關閉類。

彈框內容我控制不了,那麼我就把代碼是否更髒的職責交出去,使用了 this.props.children來作這個事情,使用者的代碼乾淨度來決定最後的業務彈框乾淨度。

具體的所有代碼可以在這裏看到:

基礎 Dialog

業務 Dialog

今天先到這裏吧,睡覺了?

相關文章
相關標籤/搜索