react-redux?mobx?或許我需要更加小巧玲瓏的

FE_xuer發表於2017-09-23

前戲

前端主流開發框架,react,vue,angular三分天下互不相讓,隨意一點火星便能引發框架大戰,但是框架選擇主觀性本身就很強,因此這裡就不評說了,一較高下不是幾句話說得清的,我個人比較喜歡react,也只是因為其他的我用的不多,也許只是先入為主那麼簡單。react帶給我們的顛覆我在這裡就不班門弄斧了,大神們已經講太多了。雖然react好用,不過始終是個基礎框架,react最大的亮點在於它的狀態管理,然鵝,使用原生react最大的不爽也是在於狀態管理。使用原生react容易造成狀態管理混亂的問題,為了解決這個問題,後來FB提出flux的思想,慢慢發展出redux,以及成熟的react-redux和mobx。個人認為react-redux很成熟很好用,有些缺點但是並不傷大雅,mobx以不同的思路來解決這個問題,而且比react-redux更加小巧一點,也不錯。不過,有時候成熟度越高,也就意味著限制越多,一些龐大的專案由於本身專案的複雜性,再引入react-redux倒是很合適,但是當我們的專案沒有大到使用react-redux這些框架,一旦引入這類框架就會發現,我其實只想要讓你管管我的狀態,但你管的太寬了,所有的路徑都給我規劃完了,比如我在客廳,需要喊一聲在臥室的老婆,我原本只是想喊一嗓子就好了,結果你也讓我打個電話,殺雞用牛刀我不反對,不過你這把刀太沉了,反而影響了我的效率這就不合適了吧。好吧,react-reudx&mobx,拜拜,我們真的不合適。

激情

既然不合適,那我們只能另覓新歡了,從react出發,或許我們可以自己倒騰一個簡單可用的狀態管理框架呢。那麼我們來分析一下我們最大的需求是什麼呢,react原生狀態管理最大的問題在哪呢?就是任意兩個元件之間通訊的問題,我需要的是兩個元件之間的通訊,是絕密的,不需要中間任何節點的感知。這當然有辦法,利用事件機制嘛,好吧,我們這次稍微不那麼low一點,既然是react的套餐,那還是要稍微要點血緣關係的。那究竟怎麼搞?我們先來整理一下思路,其實這個思路可以參考一下flux,redux的設計,我們也需要一箇中央資料中心store,對我們的資料進行集中式管理,任意節點之間的通訊其實都是通過這個store進行的。那具體如何做,讓我們迴歸本質,react的通訊是如何體現的,是由某個節點發起的某個動作導致狀態變化,然後該狀態變化同步到UI的變化,所以歸根結底,就是這個簡單的公式,store->UI。任意節點狀態的變化,對映到中央資料管理中心store,由store進行廣播出去,這就是實現了最簡單的中心化狀態管理。舉個簡單的栗子來進行說明。

舉個栗子

我定義了一個store,就是個管理state的物件,裡面有個bindContext方法,每次裝載元件的時候會把元件物件例項裝入陣列contexts,setState方法其實就是將每一個元件分別呼叫一次setState。然後我定義了一個App元件,裡面掛載Module1和Module2兩個元件,Module2下掛載一個SubModule21的子元件。當我每次需要元件之間通訊,比如SubModule21中點選“清空Module1的值”按鈕,這個就是SubModule21與Module1元件之間的通訊,其實Module1並沒有感知到是誰在對它進行操作,我們更新的其實是store中的資料狀態,並由它統一下發到元件。程式碼如下:
index.html程式碼:

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>測試</title>
</head>
<body>
<div id="page-container"></div>
</body>
</html>複製程式碼
import React from 'react';
import ReactDOM from 'react-dom';

/**
 * 統一狀態管理物件
 */
let store = {
    //目標元件物件
    contexts: [],
    //state資料
    state: {

    },
    //註冊繫結元件與狀態資料,用於setState
    bindContext(_context) {
        this.contexts.push(_context);
        return this.state;
    },
    setState(bs_state, context) {
        this.contexts.map((item) => {
            React.Component.prototype.setState.call(item, bs_state);
        })

    }
}

/**
 * 入口元件
 */
class App extends React.Component {
    constructor() {
        super();
        store.bindContext(this);
    }
    render() {
        return ( < div >
            < Module1 / >
            < Module2 / >
            < /div>
        )
    }
}

/**
 * siblings1
 */
class Module1 extends React.Component {
    constructor() {
        super();
        this.state = Object.assign({}, store.bindContext(this));
    }
    render() {
        return ( < div >
            < p > -- -- -- --Module1-- -- -- -- - < /p> < input type = "number"
            value = {
                this.state.m1Var
            }
            onChange = {
                this.setValue
            }
            /> < /div>
        )
    }
    setValue(e) {
        console.log(e.target.value);
        store.setState({
            m1Var: e.target.value
        })
    }
}

/**
 * siblings2
 */
class Module2 extends React.Component {
    constructor() {
        super();
        this.state = Object.assign({}, store.bindContext(this));
    }
    render() {
        return ( < div >
            < p > -- -- -- -- - Module2-- -- -- -- - < /p>
            兄弟節點Module1的值: {
                this.state.m1Var
            } < SubModule21 / >
            < /div>
        )
    }
}

/**
 * Module2的子元件
 */
class SubModule21 extends React.Component {
    constructor() {
        super();
        this.state = Object.assign({}, store.bindContext(this));
    }
    render() {
        return ( < div >
            < p > -- -- -- - SubModule21-- -- -- -- < /p> < button onClick = {
                this.clean
            } > 清空Module1的值 < /button> < /div>
        )
    }
    clean() {
        store.setState({
            m1Var: ""
        })
    }
}


ReactDOM.render( < App / > , document.getElementById("page-container"));複製程式碼

不知道並大家注意到沒有,這個思路一定程度上是逆react開發的,因為即使是父子元件之間,其實是沒有通過props進行聯絡的,都是統一使用setState來進行資料的下發,幾乎拋棄了props。似乎是有點問題,但是細細想來其實是沒有問題的,因為react原本就是資料驅動的,setState和props只是不同場景下傳遞資料的方式罷了,不同的設計思路,只是方式就會有所區別。核心,還是在於狀態資料的變化。

高潮

本篇只是將其中的核心思想進行簡單的呈現,相信大家會發現這段程式碼存在很多的問題,很明顯store物件存在部分邏輯問題,細細分析會發現一些亟需優化的點,並且大量存在bindContext這樣的樣板程式碼十分不優雅,不過這並不影響我們呈現核心思想。當然只有核心思想還是不夠的,需要進行繼續完善,最終的目的是完成一個簡約卻五臟俱全的框架。
好吧,這次高潮有點短暫。。。

結語

或許這個算不上一個真正的框架,可能是個非主流的玩意兒,但會讓我們在不需要redux或者mobx的時候多一種選擇。優秀的框架有很多很多,但我們不能一直只是當個使用者,我們需要一同參與建設,即使最後出來的玩意可能只有我們自己使用,這個思想或許沒人認同,那又何妨,我們知道我們比創造出這玩意之前的我們更加牛逼了。我會盡量使用react原生提供的一些特性來完成,或許可以從中發現更多react中不曾關注到的點。我相信,技術,是需要多玩玩的。

歡迎拍磚!!!

相關文章