都8102年了!是時候有個新的狀態容器取代redux了!
(不要忘了點贊轉發關注哦Q-Q!在github點個小星星!!!
rako是一個宣告式、可預測、可拓展、高內聚、簡單且強大 的JavaScript狀態容器。
與redux不同,你的專案始終需要rako!
rako能將你的業務邏輯與檢視非常好的解耦,不僅如此,因為rako鼓勵模組化,你甚至可以將檢視邏輯也寫入rako中!控制好狀態的細粒度,你的專案可維護性將會得到前所未有的提升!
github:ofollow,noindex">github.com/rabbitooops…
你可以配合例子閱讀下面的文章:codesandbox.io/s/011136qpk…
rako的設計源於最簡單的OOP程式設計 ,雖然簡單但是極具表現力。
const profile = { name: 'Tom', gender: 'male', updateName(name) { this.name = name }, updateGender(gender) { this.gender = gender } } profile.updateName('Jerry') 複製程式碼
我相信所有人都能看懂上面的程式碼,實在是太簡單了! 但是現在的功能太弱了,讓我們改造一下讓它變強,下面是我們想要的功能:
- 資料不可變。
- 每次update都引起一些副作用subscribe。
function profile(update) { return { name: 'Tom', gender: 'male', updateName(name) { update({name}) }, updateGender(gender) { update({gender}) } } } const profileStore = new Store(profile) 複製程式碼
與直接定義profile
特別相似,只不過用了一個function包裹了profile,更新使用了傳入的引數update
,但是如此簡單的設計配合一下rako就能迸發出強大的活力。
當你想得到state
時可以呼叫
profileStore.getState()
返回
{name: 'Tom', gender: 'male'}
,並且這個state
是經過
Object.freeze
處理,實現了資料不可變功能。
這與redux使用reducer定義資料有很大不同,reducer本質就是把資料的定義和更新糅合在了一起,每次動作都會由它產生返回一個新的state!這種設計有很大的問題,因為它把state的構建交給了使用者自己去實現而不是redux自身代替使用者去管理!!
需要指出的是reducer吹上天的純函式,純函式的存在是為了適應reducer的目的,每次動作都返回一個state,這導致reducer必須是純函式。
純函式的存在是為了適應reducer的設計而不是作為一個redux的優點!
所以你會發現,在真實世界中,你總是用一個東西去對接純函式!troublesome!
現在我們訂閱一個副作用:
profileStore.subscribe(state => console.log('subscribe', state)) 複製程式碼
這樣,每次update都會執行列印state。
讓我們試一下觸發更新,觸發之前,得拿到profileStore的updater :
const updater = profileStore.getUpdater() 複製程式碼
現在更新一下名字:
updater.updateName('Jerry') 複製程式碼
呼叫後,不僅會更新name
,還會觸發一次副作用,打印出
"subscribe {name: 'Jerry', gender: 'male'}"
。
這就是rako最核心的功能。
鼓勵建立多個store
rako總是鼓勵你將狀態平鋪,所以提供一個工具
createStores
去建立多個狀態容器store
。
const {profile$, contact$, theme$} = createStores({profile, contact, theme}) 複製程式碼
createStores
返回一個物件,物件的key相比傳入物件的key會
加一個
$
字尾作為
profileStore,contactStore,themeStore
的簡寫。
createStores傳入物件而不是陣列的目的是為了可拓展性。至於可拓展性方面,參考redux中介軟體,但會和redux有所不同,我稱之為enhancer,在這篇入門文章不打算深入講解複雜的東西。 況且,開發enhancer不屬於使用者關心的事情!你不需要知道任何關於開發enhancer的知識!
高內聚
現在我們聊聊高內聚。 你可以做任何初始化和非同步操作在程式碼內,
function profile(update) { // 網路請求 fetchProfile,如果網路錯誤,我未來會提供一個非常優秀的外掛去支援錯誤處理! fetchProfile().then(({name, gender}) => update({name, gender})) // 但是你不能同步update // update({name: 'Jerry'}) wrong! return { name: null, gender: null, updateName(name) { // 網路請求 setName setName(name).then(() => update({name})) }, updateGender(gender) { // 網路請求 setGender setGender(gender).then(() => update({gender})) } } } 複製程式碼
相比redux將一個簡單的邏輯寫地又臭又長,rako沒有必要寫任何樣板程式碼!你可以始終將所有業務邏輯寫在一個地方!
如果你真正的理解redux,你就會發現
dispatch、action.type、action.payload
其實和一組概念是一一對應的
:
redux | concepts |
---|---|
dispatch | 呼叫函式 |
action.type | 函式名 |
action.payload | 函式的引數 |
dispatch({type: 'SET_NAME', payload: 'Jerry'}) 複製程式碼
完全等價於
setName('Jerry') 複製程式碼
說白了,redux是把一個函式的呼叫複雜化!
不僅於此,由於action.type是一個字串,所以不論action.type是否正確都會觸發一次更新,究其根本是一個不可靠的函式呼叫,你必須人力去維護一組action.type,而且要保證你的每一次dispatch都要正確執行正確的字串action.type。
rako並不採用如此設計,如果你想更新,直接呼叫updateName即可,你想呼叫一個不存在的更新是不可能的,一句話總結就是redux提供人工級維護,rako提供語言級維護。
在react中使用
好啦!介紹一下rako如何在react中使用!我將rako-react設計得如此簡單以至於只有兩個API ,甚至在大部分時候只需要一個API就能輕鬆將store注入進component中!
啟用decorator:
import {assign, prop} from 'rako-react' @assign( prop(profile$, state => state), contact$ ) class App extends React.Component {} 複製程式碼
沒啟用decorator:
export default assign( prop(profile$, state => state), contact$ )(App) 複製程式碼
prop
第一個引數是store
,第二個引數是mapper
,mapper
是一個函式,會將store的state和updater傳入其中,返回一個新的object
,預設是:
(state, updater) => Object.assign({}, state, updater) 複製程式碼
assign
接受任意prop
或者store
甚至object
,它會將多個狀態平鋪開來,傳入App
。在function component中,你始終不需要prop,你可以這樣寫:
function App({name, gender, phone}) { // TODO } App = assign(profile$, contact$)(App) 複製程式碼
未來,等到react 16.7正式推出hook,rako將支援useProp
寫法!
const {name, gender, updateName, updateGender} = useProp(profile$) 複製程式碼
如果你認為rako足夠優秀,為了讓更多的人看到,也為你以後有機會在專案中使用rako,請一定要點個贊,在github點一個star!!!
Welcome more creative ideas!