redux 及在Android上應用 rekotlin

什么是redux

redux 的概念來源于前端,是一個“可預測的狀態(tài)容器”,采用“單向數(shù)據(jù)流”的思想,目的是為了讓JS的狀態(tài)管理變得更加可預期。

為什么使用redux

redux 存在的目的是為了解決組件之間的通信以及集中保存管理項目的狀態(tài)。隨著項目變得越來越大,組件之間的通信越來越復雜,狀態(tài)越來越多,項目就變得難以維護。
使用redux管理狀態(tài),是將所有狀態(tài)都保存在store中,各組件可以直接從store中獲取到自己需要的狀態(tài)。這樣將全局狀態(tài)保存到一處統(tǒng)一管理,使項目更加容易維護,組件之間的通信更加清晰。

不使用Redux和使用Redux時父子組件之間的通信方式
  • 沒有使用Redux的情況,如果兩個組件(非父子關系)之間需要通信的話,可能需要多個中間組件為他們進行消息傳遞,這樣既浪費了資源,代碼也會比較復雜。
  • Redux中提出了單一數(shù)據(jù)源Store用來存儲狀態(tài)數(shù)據(jù),所有的組件都可以通過Action修改Store,也可以從Store中獲取最新狀態(tài),使用redux可以完美解決組件之間的通信問題。

4 張動圖解釋為什么(什么時候)使用 Redux

redux的核心概念及rekotlin的應用

redux的工作流程


rekotlin的工作流程

Store

  • Store可以看作一個狀態(tài)容器,一個應用只能有一個Store。Store提供一些方法用于存取狀態(tài),分發(fā)狀態(tài)及注冊監(jiān)聽。以下是rekotlin中對于Store的接口定義中的幾個常用方法
interface StoreType<State: StateType>: DispatchingStoreType {

    /**
     * 當前Store中存儲的State
     */
    val state: State

    /**
     * 所有方便的 `dispatch` 方法使用的主要調(diào)度函數(shù)。
     * 這個調(diào)度功能可以通過提供中間件來擴展。
     * typealias DispatchFunction = (Action) -> Unit
     */
    var dispatchFunction: DispatchFunction

    /**
     * 將訂閱者注冊到Store,當Store中的State發(fā)生改變時,訂閱者的`newState`方法將被調(diào)用
     */
    fun <S: StoreSubscriber<State>> subscribe(subscriber: S)

    /**
     * 解注冊訂閱者,State更新時訂閱者將不再收到通知
     */
    fun <SelectedState> unsubscribe(subscriber: StoreSubscriber<SelectedState>)

    /**
     * 分發(fā)一個Action用于修改Store中的State
     *(這是DispatchingStoreType中定義的方法)
     */
    fun dispatch(action: Action)
    
    ···
}

State

  • State代表狀態(tài),是某個時刻表示一個View渲染所需所有數(shù)據(jù)狀態(tài)的集合,實際上是一個狀態(tài)樹。
    Redux 規(guī)定,一個 State 對應一個 View。只要 State 相同,View 就相同。你知道 State,就知道 View 是什么樣,反之亦然。
interface StateType

data class ViewState(
    // 表示當前State對應的View中渲染所需內(nèi)容
    val isVisible: Boolean = true,
    val titleText: String = "title",
    // 表示子View對應的State,形成一個狀態(tài)樹
    val statusLayerState: StatusLayerState? = null,
    val businessLayerState: BusinessLayerState? = null
) : StateType

kotlin中使用data class表示State,方便進行copy()操作

Action

  • State 的變化,會導致 View 的變化。但是,用戶接觸不到 State,只能接觸到 View。所以,State 的變化必須是 View 導致的。Action 就是 View 發(fā)出的通知,表示 State 應該要發(fā)生變化了。
/**
 * 所有被分發(fā)的Action都需要實現(xiàn)這個接口
 */
interface Action

class ViewVisibleAction(val isVisible: Boolean) : Action

Reducer

  • Store 收到 Action 以后,必須給出一個新的 State,這樣 View 才會發(fā)生變化。這種 State 的計算過程就叫做 Reducer。
  • Reducer 是一個純函數(shù),它接收 Action 和當前 State 作為參數(shù),返回一個新的 State。
fun viewReducer(action: Action, viewState: ViewState?): ViewState {
      var newState = viewState ?: viewState()
      when(action) {
            is ViewVisibleAction -> {
                  newState = newState.copy(isVisible = action.isVisible)
            }
      }
      newState = newState.copy(statusLayerState = statusLayerReducer(action, viewState?.statusLayerState))
      newState = newState.copy(businessLayerState = businessLayerReducer(action, viewState?.businessLayerState))
      return newState
}

fun statusLayerReducer(action: Action, statusLayerState: StatusLayerState?): StatusLayerState {
      ···
}

fun businessLayerReducer(action: Action, businessLayerState: BusinessLayerState?): BusinessLayerState {
      ···
}

Reducer 函數(shù)最重要的特征是,它是一個純函數(shù)。也就是說,只要是同樣的輸入,必定得到同樣的輸出。
由于 Reducer 是純函數(shù),就可以保證同樣的State,必定得到同樣的 View,任何時候,與某個 View 對應的 State 總是一個不變的對象。但也正因為這一點,Reducer 函數(shù)里面不能改變 State,必須返回一個全新的對象。因而State最好是只讀的。

高階用法 Middleware

  • Middleware中間件,在store.dispatch()分發(fā)Action到Reducer之間被調(diào)用,常用于添加、改造功能。


// typealias別名,僅做內(nèi)聯(lián)替換,不生成新的函數(shù)
typealias DispatchFunction = (Action) -> Unit
typealias Middleware<State> = (DispatchFunction, () -> State?) -> (DispatchFunction) -> DispatchFunction

class viewMiddleware(): Middleware<ViewState> {
    override fun invoke(
        p1: DispatchFunction,
        p2: () -> ViewState?
    ): (DispatchFunction) -> DispatchFunction {
        return fun(next: DispatchFunction): (Action) -> Unit {
            return fun(action: Action) {
                next(action)
            }
        }
    }
}

Store中dispatchFunction的實現(xiàn)

    override var dispatchFunction: DispatchFunction = middleware
            .reversed()
            .fold({ action: Action -> this._defaultDispatch(action) }, { dispatchFunction, middleware ->
                val dispatch = { action: Action -> this.dispatch(action) }
                val getState = { this._state }
                middleware(dispatch, getState)(dispatchFunction)
            })

redux的三大原則

  • Single source of truth 單一數(shù)據(jù)源
    • The global state of your application is stored in an object tree within a single store. 應用的全局狀態(tài)以樹的形式存儲在單一store中
  • State is read-only 狀態(tài)只讀
    • The only way to change the state is to emit an action, an object describing what happened. 唯一改變state的方式是發(fā)送一個表示發(fā)生了什么的action
  • Changes are made with pure functions 變化由純函數(shù)計算
    • To specify how the state tree is transformed by actions, you write pure reducers. 編寫純函數(shù)去通過actions計算state發(fā)生了什么變化

redux使用場景

“如果你不知道是否需要 Redux,那就是不需要它。”

  • 如果你的UI層非常簡單,沒有很多互動,redux 就是不必要的,用了反而增加復雜性。在應用程序增長到管理狀態(tài)變得麻煩的規(guī)模的情況下,可以使用redux,使狀態(tài)管理和溯源變得容易和簡單。所以總體原則是能不用就不用, 實在干不動了再用。
  • 某個組件的狀態(tài),需要共享。
  • 某個狀態(tài)需要在任何地方都可以拿到。
  • 一個組件需要改變?nèi)譅顟B(tài)。
  • 一個組件需要改變另一個組件的狀態(tài)。

使用redux的優(yōu)勢

狀態(tài)可預測:相同的State和Action傳遞給Reducer,輸出的結果總是相同的(純函數(shù)特性)。且當你需要修改狀態(tài)時,必須重新開始走一個修改的流程,這種限制狀態(tài)修改的方式,讓狀態(tài)變得可預測,容易調(diào)試。
可維護性:具有 Redux 知識的人更容易理解任何 Redux 應用程序的結構,且有助于用戶將業(yè)務邏輯與組件樹分離。
單向數(shù)據(jù)流:所有狀態(tài)的改變可記錄、可跟蹤,源頭易追溯,數(shù)據(jù)具有唯一出口和入口,使得數(shù)據(jù)操作更直觀更容易理解。

引申

單向數(shù)據(jù)流和雙向綁定的優(yōu)缺點對比

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容