這是 Pastate.js 響應式 react state 管理框架系列教程,歡迎關注,持續更新。javascript
Pastate 的核心是一個管理不變式和響應式 state 的 pastore, 下面來詳細介紹 pastore 的內容。vue
Pastore 內部使用一種獨特的帶路徑信息且不可變(immutable)的 state 做爲應用的數據源, 掛載在 store 的 imState 屬性上。在實現上,Pastore 把非空數據源都轉化爲包裝類型,具體流程以下圖,以 string 類型的節點爲例:java
其中 __store__
爲 state 所在的 store 實例的引用,__xpath__
爲該 state 節點在當前 store 的 state 的路徑,如 __xpath__ == '.foo.bar.baz'
。react
Pastate 使用一種自定義的具備 immutable 特性的數據類型, 而不是 immutable.js 的數據類型。 Immutable 特性指的是數據是不可變的,新的數據只能根據老的不可變數據去從新組合而成,下面舉個例子:git
/** 可變數據 */ let mutableData = { foo: 'good', bar: 'very good' } // 可使用直接賦值的模式去改變數據 mutableData.foo = 'so good' newData = mutableData /** 不可變數據 */ let immutableData = { foo: 'good', bar: 'very good' } // 不可修改老數據,須要根據老數據去構建新數據 newData = Object.assgin({}, immutableData, {foo: 'so good'}) // 可使用 ES6 的 Object.assgin 函數 newData = {...immutableData, foo: 'so good'} // 也可使用 ES7 的對象擴展符
immutableData 實現了兩種效果:github
若是咱們手動實現 immutable state 的更新邏輯,會很是麻煩,假設有這樣一個 state :typescript
let state = { foo: { bar: { baz: { name: 'Peter' } } }, } // 咱們手動來修改 name 屬性的值 // 1. 若是是 mutable data state.foo.bar.baz.name = 'Tom' newData = state // 2. 若是是 immutable data newData = Object.assgin({}, state, Object.assgin({}, state.foo, Object.assgin({}, state.foo.bar, Object.assgin({}, state.foo.bar.baz, { name: 'Tom' }) ) ) )
可見,在手動更新 immutble data 的深層嵌套數據時,很是麻煩!並且若是有多個相同或不一樣嵌套深度的 state 節點須要更改,且這些更改時在運行上連續進行的可是在代碼上是封裝開的,容易致使重複進行沒意義的引用更新:npm
let state = { foo: { bar: { baz: { name: 'Peter' }, id: '1234' } }, } // 咱們封裝 name 的修改邏輯 function changeName(){ Object.assgin..., Object.assgin..., Object.assgin..., Object.assgin... } // 咱們封裝 age 的修改邏輯 function changeAge(){ Object.assgin..., Object.assgin..., Object.assgin... } function handleClick(){ shouldChangeName && changeName() shouldChangeAge && changeAge() }
上面的代碼,在 handleClick 的實現邏輯中,是否修改 name 或 age 是有可能單獨或同時發生的,通常咱們會把修改邏輯獨立封裝並按需調用。若是某個狀況下須要連續運行 changeName 和 changeAge, 那麼在 changeAge 中的 3 個 Object.assgin 是重複的,沒有實際意義。編程
你可能會考慮使用 immutable.js 庫的數據結構,immutable.js 提供完善的 immutable 數據類型和操做方式支持,但在 react 項目中使用 immutable.js 有如下不足:redux
imState.setIn(['info', 'basic', 'name'], 'new Name')
,而不是用原生 JS 對象屬性模式來索引節點, 如 state.info.basic.name
。所以編輯器沒法分析可選屬性,也沒法索引結果的類型,這使得編程起來效率低,並且比較容易出錯。所以,Pastate 在每一個 state 節點附加了 節點路徑信息 ,並實現 state 的自動化 immutable 且按需更新引用的功能!讓咱們能夠享受 immutable 數據的優點的同時,拋開使用 immutable 數據的複雜性。
Pastore 內部實現了一個異步操做(operation)列表,並定義了一套 operation 壓入方法:
set(imState.foo.bar, newValue)
merge(imState.foo, {bar: newValue})
update(imState.foo.bar, n => n+ '!')
這三個方法會向 store 提交一個 operation, store 把收到 operation 後,暫時存在一個 operation 隊列中,在下一個事件循環(event loop)時對 operation 隊列進行統一處理,再批量處理中實現按需引用更新,具體流程圖以下:
在每一個 operation 被 push 的先後及在 operation 被 reduce 的先後,pastate 都設計了相應的生命週期函數,你能夠經過這些生命週期函數接收、過濾或控制operation,實現自定義邏輯。
stateWillAddOperation
將要增長 operation 時會被調用stateWillReduceOperations
將要執行 operations 時會被調用stateWillApplyOperation
將要執行一個 operation 時會被調用stateDidAppliedOperation
執行完一個 operation 後會被調用stateDidReducedOperations
執行完 operations 時執行詳見 API文檔。
直接使用 set(imState.foo.bar, newValue)
或 merge(imState.foo, {bar: newValue})
等來進行 immutable state 的操做雖然已經挺方便,但和咱們平時修改 js 變量的模式仍是不太同樣,所以 pastate 爲 immutable state 構建了一套響應式的鏡像 state 來自動調用 set、merge、或 update 來生成 operation, 使得咱們能夠用賦值符號 =
或數組操做參數如 push
、pop
等來間接地對 immutable state 進行操做,對於處學者來講無需任何學習成本。 Pastate 內部使用 Object.defineProperty 的方式爲響應式 state 節點定義相應的 getter 和 setter, 以實現經過賦值或數組函數發起 set, merge 或 update operation,對接 pastate 異步 operation 處理引擎,流程圖以下:
當 pastore 完成一批 operations 的 reduce 過程時,會對外發出一個視圖更新信號,經過 pastore 的 dispatch 成員函數發出。Pastate 內部實現了 pastate-redux 鏈接器, 默認使用 redux 做爲 state 發生改變時的響應器,並由 react-redux 去鏈接 react 組件組件,從而實現 pastate-react。同時, pastate 使用 redux 的基本規則實現多模塊邏輯,所以,你可使用 redux 生態系統相關組件或開發工具類配合 pastate 應用,咱們很是擁抱 redux 生態系統。
另外一方面,你徹底能夠自行實現一套視圖響應邏輯, 甚至實現 pastore 與 vue 或 angular 對接,歡迎嘗試。
Pastate 使用 typescript 進行開發,具備完善的類型支持,能夠直接引入 pastate 並直接在 React Typescript 項目中使用。
咱們正嘗試在 react-native 中使用 pastate, 你也能夠加入嘗試,若是發現什麼問題,歡迎提交 issue 告訴咱們~
Pastate 在原理上能夠與類 react (react alternative) 框架如 preact 或 nerv 配合使用,但未進行全面測試,若是你嘗試了,歡迎提交 issue 告訴咱們~
敬請期待,若是你基於 pastate 開發一些項目,歡迎提交 issue 告訴咱們~
$ git clone <your repo> $ cd pastate $ yarn install
$ yarn start
$ yarn test
$ yarn dist
目標代碼會編譯到 /dist 目錄下
若是以爲 pastate 很是不錯,歡迎參與 pastate 文檔英文翻譯計劃,讓更多的國外友人也能嘗試 pastate 。若是你有意願,請在 github 聯繫。