該專案旨在透過實現自訂模式來減輕 SPA 開發中的痛苦,該模式以與框架無關、易於測試且對開發人員友好的方式對應用程式狀態進行建模。 Sparix 可讓您將狀態封裝在類型安全的儲存中,並定義可以在所述狀態上發生的轉換。更新永遠不會改變狀態,而是建立一個新的狀態轉換實例(就像 redux 減速器一樣)。轉換後的狀態序列以 RxJS Observable<State>
公開提供。
Sparix 是用 TypeScript 編寫的,程式碼範例也是如此。它作為 JavaScript 庫進行分發,類型定義嵌入在 NPM 模組中,就像 RxJS 一樣。
$ npm i -S sparix rxjs
import { Store } from 'sparix'
import { add } from 'ramda'
export interface CounterState {
count : number
}
const initialState : CounterState = {
count : 0
}
export class Counter extends Store < CounterState > {
constructor ( ) {
super ( initialState )
}
increment ( ) {
// ALL THESE ARE EQUIVALENT
this . update ( state => { count : state . count + 1 } )
this . updateState ( { count : val => val + 1 } )
this . updateState ( { count : add ( 1 ) } ) // Using Ramda's automatically curryied functions
}
}
import { Counter , CounterState } from './counter'
const counter = new Counter ( )
// Recommended way
const state$ : Observable < CounterState > = counter . state$
const count$ : Observable < number > = counter . map ( state => state . count )
// Alternative way (useful for testing)
expect ( counter . currentState . count ) . toEqual ( 0 )
counter . increment ( )
expect ( counter . currentState . count ) . toEqual ( 1 )
首先,它是一種模式。其次,它是基於RxJS的實作。實作非常簡單,用另一個反應式庫重寫它只需要幾個小時。然而,由於 SPA 世界將由 React 和 Angular2 主導,而且後者附帶 RxJS,因此使用該程式庫作為 sparix 的參考實作是有意義的。
在 sparix 中,狀態被建模為Observable<State>
,即狀態轉換的不可變流。
Store 的 API 保持簡單,所有複雜的邏輯都被封裝並從外部隱藏,就像使用古老的物件導向程式設計一樣。要測試 Store,您所需要做的就是模擬輸入(透過呼叫其公共方法之一)並檢查其輸出(狀態)。
Sparix 完全遵循 redux 原則(或更確切地說,Elm 架構原則),其中狀態轉換被定義為不會改變先前狀態的純函數。
在 redux 中,當您需要更新狀態時,您可以調度一個操作。但如果仔細觀察,您可能會發現操作可以分為兩類:
我的主張是,當目標只是更新單一 Store 的狀態(在大多數情況下)時,操作是一種過於繁重的機制。在 sparix 中,Store 可以直接更新其狀態,無需更多儀式:
// Increment counter
this . update ( state => ( {
counter : state . counter + 1
} ) )
有一種更細粒度、更具聲明性的方式來編寫這些狀態更新器:
this . updateState ( {
counter : prevCounter => prevCounter + 1
} )
或甚至更好:
const increment = value => value + 1
this . updateState ( {
counter : increment
} )
好吧,實際上你應該利用 Ramda 的自動柯里化:
import { add } from 'ramda'
this . updateState ( {
counter : add ( 1 )
} )
我喜歡將這些狀態更新程式視為匿名操作。在 redux 中,這就像調度一個減速器。但動作創作者呢?好吧,我們真的不需要它們:
const increment = val => val + 1
class SomeStore extends Store < SomeState > {
// constructor
incrementCounter ( ) {
this . updateState ( {
counter : increment
} )
}
}
這裡, incrementCounter()
方法是Store公共API的一部分。您不再需要分派由操作創建者建立的全域操作。只需呼叫方法即可!
Sparix 致力於對應用程式的核心進行建模。但什麼是核心呢?或者更確切地說,什麼不是核心?
應用核心應該是不可知的。與框架和資料庫無關,與表示層無關,與資料獲取機制和協定無關。它應該對一切都是不可知的。
應用程式核心不知道 HTML、DOM、Angular 或 React、本地儲存、HTTP 或 WebSockets.. 它甚至不知道它存在於 Web 瀏覽器中!相同的應用程式核心應該可以在 Cordova、NativeScript 或 Electron 應用程式中重複使用,而無需更改一行程式碼!
那你在核心中放了什麼?答案很簡單:其他一切!如果它可以成為核心的一部分,那麼它就應該成為核心的一部分。所有的業務邏輯、資料轉換、互動邏輯都應該建模為應用程式核心。除了用於建模的程式語言之外,所有這些都不應該依賴其他任何東西。
回到sparix。它將幫助您建模不依賴第三方程式庫和框架的應用程式核心,但 RxJS 和 sparix 本身除外。但這不是什麼大問題。 Observables 正在成為標準 ECMAScript 功能,而 sparix 是一個非侵入式函式庫,這使得使用它可以輕鬆地僅對應用程式核心的子集進行建模。