介紹
redux 有三個重要的組成部分,分別是:provider,store,reducer,其中reducer和store負責接收我們自定的action,處理並且返回新的state,然後重新整理介面。
而在應對複雜業務場景的情況下,常用的則是:combineReducers和Middleware來處理多業務場景以及複雜的非同步處理等。combineReducers可以封裝多個reducer,來實現action的細粒度控制,middleware則通過攔截action的方式達到優先於reducer執行的目的。
除此之外,和provider的selector類似的,flutter_redux還提供了distinct控制,來判斷是否真的需要重新整理檢視。
中介軟體的實現原理
常需要在其中呼叫next或者dispatch轉發,否則沒有意義,一些靜默行為除外。
combineReducers和Middleware 實現原理類似,都是通過實現並重寫Dart的call函式,是類的例項函式化,在其中判斷型別,進而呼叫入參函式。
@override
dynamic call(Store<State> store, dynamic action, NextDispatcher next) {
if (action is Action) {
return middleware(store, action, next);
} else {
return next(action);
}
}
複製程式碼
@override
State call(State state, dynamic action) {
if (action is Action) {
return reducer(state, action);
}
return state;
}
複製程式碼
combineReducers
combineReducers的實現較為簡單,直接for in 迴圈遍歷並呼叫。
Reducer<State> combineReducers<State>(Iterable<Reducer<State>> reducers) {
return (State state, dynamic action) {
for (final reducer in reducers) {
state = reducer(state, action);
}
return state;
};
}
複製程式碼
Middleware中介軟體需要在reducer之前呼叫,可以看下store的dispath實現:
/// _dispatchers 的初始化
List<NextDispatcher> _createDispatchers(
List<Middleware<State>> middleware,
NextDispatcher reduceAndNotify,
) {
/// 將reducer加入到dispatchers中 [reducer]
final dispatchers = <NextDispatcher>[]..add(reduceAndNotify);
// Convert each [Middleware] into a [NextDispatcher]
/// 將中介軟體加入到dispatchers中 [reducer , middlewares ...]
for (var nextMiddleware in middleware.reversed) {
final next = dispatchers.last;
dispatchers.add(
(dynamic action) => nextMiddleware(this, action, next),
);
}
/// 反轉陣列,將中介軟體放到最前邊 [middlewares ... , reducer]
return dispatchers.reversed.toList();
}
/// store呼叫dispatch
dynamic dispatch(dynamic action) {
return _dispatchers[0](action);
}
複製程式碼
可以看到每次store呼叫dispatch的時候,都會從_dispatchers的第一個元素開始呼叫,而middleware中介軟體是類似連結串列的資料結構,next 儲存著下一個的中介軟體呼叫。
通過原始碼可以得知,在中介軟體中,我們可以攔截相同Action的Reducer,並通過next呼叫reducer,甚至可以通過dispatch進行轉發。
distinct 的作用原理
StoreConnector中的distinct
redux是通過流(StreamBuilder)來控制檢視重新整理的,檢視通過呼叫store.dispatch(action),來觸發流,然而redux的流控制並不像bloc一樣直接暴露給我們使用,而是自己針對流做了一系列的控制
void _createStream() {
_stream = widget.store.onChange
.where(_ignoreChange)
.map(_mapConverter)
// Don't use `Stream.distinct` because it cannot capture the initial
// ViewModel produced by the `converter`.
.where(_whereDistinct)
// After each ViewModel is emitted from the Stream, we update the
// latestValue. Important: This must be done after all other optional
// transformations, such as ignoreChange.
.transform(StreamTransformer.fromHandlers(
handleData: _handleChange, handleError: _handleError));
}
複製程式碼
- 首先是提供了ignoreChange,可以根據state,來控制是否忽略本次重新整理
- 然後是提供converter返回vm
- 如果distinct為true的化,比較新舊vm,判斷是否需要重新整理介面。否則強制重新整理。
store中的distinct
在構建store的時候,會發現,store也提供了一個distinct,它的實現作用更為簡單粗暴:
NextDispatcher _createReduceAndNotify(bool distinct) {
return (dynamic action) {
final state = reducer(_state, action);
if (distinct && state == _state) return;
_state = state;
_changeController.add(state);
};
}
複製程式碼
在呼叫reducer之後,直接判斷新舊state是否相等,來控制流的傳送。
這兩個distinct都有控制重新整理的作用,區別在於StoreConnector中的distinct可以通過converter來控制判斷粒度,來實現變數級的重新整理控制,而store中的distinct僅僅適用於函式級。
如何優化?
1.通過distinct的原始碼實現,不難發現,他們的控制都是通過比較state或者vm來實現的,我們可以通過過載"=="方法來進行更加靈活的重新整理控制。
2.redux通過流實現,預設是非同步流,可以通過更改syncStream來實現同步流。