都8102年了!是時候有個新的狀態容器取代redux了!

rabbitooops發表於2018-11-02

(不要忘了點贊轉發關注哦Q-Q!在github點個小星星!!!

rako是一個宣告式、可預測、可擴充、高內聚、簡單且強大的JavaScript狀態容器。

與redux不同,你的專案始終需要rako!

rako能將你的業務邏輯與檢視非常好的解耦,不僅如此,因為rako鼓勵模組化,你甚至可以將檢視邏輯也寫入rako中!控制好狀態的細粒度,你的專案可維護性將會得到前所未有的提升!

github: 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')
複製程式碼

我相信所有人都能看懂上面的程式碼,實在是太簡單了! 但是現在的功能太弱了,讓我們改造一下讓它變強,下面是我們想要的功能:

  1. 資料不可變。
  2. 每次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,第二個引數是mappermapper是一個函式,會將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!!!

github.com/rabbitooops…

github.com/rabbitooops…

Welcome more creative ideas!

相關文章