什么是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可以完美解決組件之間的通信問題食棕。
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` 方法使用的主要調度函數(shù)甥捺。
* 這個調度功能可以通過提供中間件來擴展。
* typealias DispatchFunction = (Action) -> Unit
*/
var dispatchFunction: DispatchFunction
/**
* 將訂閱者注冊到Store镀层,當Store中的State發(fā)生改變時镰禾,訂閱者的`newState`方法將被調用
*/
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中渲染所需內容
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之間被調用嗦明,常用于添加笼沥、改造功能。
// typealias別名娶牌,僅做內聯(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)需要在任何地方都可以拿到。
- 一個組件需要改變全局狀態(tài)虱岂。
- 一個組件需要改變另一個組件的狀態(tài)玖院。
使用redux的優(yōu)勢
狀態(tài)可預測:相同的State和Action傳遞給Reducer,輸出的結果總是相同的(純函數(shù)特性)第岖。且當你需要修改狀態(tài)時难菌,必須重新開始走一個修改的流程,這種限制狀態(tài)修改的方式蔑滓,讓狀態(tài)變得可預測郊酒,容易調試。
可維護性:具有 Redux 知識的人更容易理解任何 Redux 應用程序的結構键袱,且有助于用戶將業(yè)務邏輯與組件樹分離燎窘。
單向數(shù)據(jù)流:所有狀態(tài)的改變可記錄、可跟蹤蹄咖,源頭易追溯褐健,數(shù)據(jù)具有唯一出口和入口,使得數(shù)據(jù)操作更直觀更容易理解比藻。