一個簡潔且強大的狀態管理庫 - iFlow

unadlib發表於2018-01-30

前言

以React為主的開發過程中,用過主流的兩大狀態管理工具Redux和Mobx。但在我使用它們時,逐漸地感覺到了一些不太好的地方:Redux使用過程有點冗餘和拖沓,而儘管Redux也有中介軟體,但Redux帶來的收益和它官方說的一樣:僅僅只是一個純的狀態容器而不是狀態管理;而基於Observable的狀態管理庫Mobx則侵入性強,且丟失狀態型別的原始性(被Observable例項化),以及因此而導致一系列限制與困擾。

所以,我慢慢開始期待有一個更好的狀態管理庫出現。我希望它基於Mutable結構,狀態操作高效直接,而且不應破壞狀態資料型別的原始性;同時它也支援Immutable輸出,兼顧Mutable的有利於程式設計和操作;然後它應該是漸進式的,可以是簡潔的,也能是強大的,不會因過多的繁瑣冗餘操作以及複雜概念而破壞程式設計樂趣。

是的,它應該是簡潔且強大的。

因此,我試著構建一個這樣狀態管庫 -- iFlow

簡介

iFlow是動態的和可擴充套件的, 你可以直接使用它來新增、刪除和修改State和Action;它是Mutable結構, 支援普通function和class, 並易於物件導向程式設計;同時它沒有任何依賴包,且非常小(5k)。需要特別說明的是iFlow定義的Store是包括Actions和State。如果你是剛涉獵狀態庫,那麼在快速閱讀文件後就可以讓你在幾分鐘內就能開始構建你的App了,因為它是極簡單的;但如果你諳熟各種狀態庫,那麼它也能讓你得心應手,或許你會驚喜的發現,iFlow有些特效能高效實現出其他狀態庫不太好實現的架構設計。

從原理上說,iFlow是基於ECMAScript 2015的Proxy & Reflect。它構建的Paths Match大致過程是:先在View元件進行引用Store的State的時候獲得Getter Paths;然後在Action被觸發的時候,將通過Proxy得到Setter Path;最後,在通過觀察者來傳遞Setter Path,並在聯結器內進行快速地Getter Paths Match來控制更新View元件。

  • 流程圖

流程圖

抽象化公式來表達就是: action(store) => store = newStore

基本概念

  • Store

它包含State和Actions,是State管理應用的具體部分,它可以是普通物件的形式,也可以是class的形式。

const store = iFlow({
  add (number) {
    this.counter += number
  },
  counter: 0,
}).create()複製程式碼

或者是

class Counter {
  constructor () {
    this.counter = 0
  }
  add (number) {
    this.counter += number
  }
}
const store = iFlow(new Counter()).create()複製程式碼
  • 中介軟體(Middleware)

iFlow提供了好幾種不同型別的中介軟體用於控制不同流程下的Action執行和State改變,它能控制幾乎State和Action的一切行為。

const store = iFlow({
  add (number) {
    this.counter += number
  },
  counter: 0,
}).middleware({
  stateDidChange (...args) {
    // 狀態變化後通知中介軟體
  }
}).create()複製程式碼
  • 聯結器(Connector)

iFlow配合react-iflow聯結器,可以讓Store和View層連線,iflow的聯結器是簡單高效的。

class Example extends Component {
  render () {
    return <div onClick={() => this.props.store.add(1)}>{this.props.store.counter}</div>
  }
}
export default flow(store)(Example)複製程式碼

特性

  • ?支援普通function和class - 它很簡單,同時也可設計符合各種需求狀態管理架構。
  • ?Store組合 - Store Tree可以很容易共享操作Store節點。
  • ⚡動態和熱插拔 - 可自由插拔State和Action。
  • ?支援非同步function以及其他型別的function - 可任意組合Action或由內部其他內部Action相互組合。
  • ?強大的中介軟體 - 中介軟體可以攔截控制和處理全部的State變化和Actions執行。
  • ?Store支援immutable - Store是支援被處理成immutable的Store。

優點

  • 保持資料結構的原始性

iFlow因為利用ES6 Proxy機制,因此可以保持資料結構的完整原始性,同時支援非同步函式以及其他型別函式,當然也包括普通的類和函式。

  • 無樣板程式碼

iFlow能給你比較自由的使用它來實現屬於符合實際開發需求的狀態資料結構設計,而不會因為各種庫的限制來變成有過多的樣板程式碼。

  • 易於物件導向

有時當我們需要解耦業務程式碼,尤其是中大型的專案中,我們可能需要一些物件導向程式設計當設計,所以狀態庫如果能支援它當然是更好了。

  • 儘可能少的選擇器

在使用Web框架(如React)的時候,iFlow是自動匹配更新的,與之對應的連線庫react-iflow可以讓你能儘可能少一些選擇器的編寫與操作,甚至在大多數情況下,使用iFlow時,你不需要選擇器。

  • 強大的中介軟體

如果有必要,事實上iFlow中介軟體是強大且有用的,完整的中介軟體:stateWillInitialize / actionWillStart / stateWillChange / stateDidChange / actionDidEnd,它們能實現各種需求下的狀態管理設計; 同時它也可以實現一些基礎性中介軟體,例如持久化中介軟體等等.

  • 可組合和可伸縮的Store

iFlow提倡將Store組合成store tree,不用擔心無關的Store造成一些效能上的影響,因為它是動態匹配的,你可以放心自由的組合和擴充Store。

示例

  • 簡單計數器

我們來構建一個簡單的計數器:

const store = iFlow({
  calculate (number) {
    this.counter += number
  },
  counter: 0,
}).create()

@flow(store)
class Counter extends Component {
  render() {
    return (
        <div>
        <button onClick={() => this.props.store.calculate(-1)}>-</button>
        {this.props.store.counter}
        <button onClick={() => this.props.store.calculate(1)}>+</button>
      </div>
    );
  }
}複製程式碼

線上執行

  • TODO

接著我們來實現一個複雜點的TODO(帶撤銷/重做/持久化)

線上執行

尾聲

最後,iFlow希望能為開發者解決在狀態管理架構和設計上可能需要的困擾,小型專案能夠更簡單輕量化,大型專案又能夠高效地各種深度設計。

如果你對iFlow感興趣的話,非常歡迎來嘗試看看,同時也非常歡迎提交PR和issue。

目前iFlow部分文件已提供,同時後續文件也將繼續完善中。

如果感覺它還不錯,特別歡迎給iFlow一個star⭐️,謝謝鼓勵!!!

github.com/unadlib/ifl…


相關文章