Fish Redux中的Dispatch是怎麼實現的?
開源地址:
我們在使用fish-redux構建應用的時候,介面程式碼(view)和事件的處理邏輯(reducer,effect)是完全解耦的,介面需要處理事件的時候將action分發給對應的事件處理邏輯去進行處理,而這個分發的過程就是下面要講的dispatch, 透過本篇的內容,你可以更深刻的理解一個action是如何一步步去進行分發的。
為了更好的理解action的dispatch過程,我們就先以todolistpage中一條todo條目的勾選事件為例,來看點選後事件的傳遞過程,透過斷點debug我們很容易就能夠發現點選時候發生的一切,具體過程如下:
使用者點選勾選框,GestureDetector的onTap會被回撥
透過buildView傳入的dispatch函式對doneAction進行分發,發現todo_component的effect中無法處理此doneAction,所以將其交給pageStore的dispatch繼續進行分發
pageStore的dispatch會將action交給reducer進行處理,故doneAction對應的_markDone會被執行,對state進行clone,並修改clone後的state的狀態,然後將這個全新的state返回
然後pageStore的dispatch會通知所有的listeners,其中負責介面重繪的_viewUpdater發現state發生變化,通知介面進行重繪更新
Dispatch在fish-redux中的定義如下
typedef Dispatch = void Function(Action action);
本質上就是一個action的處理函式,接受一個action,然後對action進行分發。
下面我門透過原始碼來進行詳細的分析。
01 component中的dispatch
buildView函式傳入的dispatch是對應的component的mainCtx中的dispatch,
_mainCtx和componet的關係如下 component->ComponentWidget->ComponentState->_mainCtx->_dispatch
而 _mainCtx的初始化則是透過componet的createContext方法來建立的,順著方法下去我們看到了dispatch的初始化
// redux_component/context.dart DefaultContext初始化方法
DefaultContext({
@required this.factors,
@required this.store,
@required BuildContext buildContext,
@required this.getState,
}) : assert(factors != null),
assert(store != null),
assert(buildContext != null),
assert(getState != null),
_buildContext = buildContext {
final OnAction onAction = factors.createHandlerOnAction(this);
/// create Dispatch
_dispatch = factors.createDispatch(onAction, this, store.dispatch);
/// Register inter-component broadcast
_onBroadcast =
factors.createHandlerOnBroadcast(onAction, this, store.dispatch);
registerOnDisposed(store.registerReceiver(_onBroadcast));
}
context中的dispatch是透過factors來進行建立的,factors其實就是當前component,factors建立dispatch的時候傳入了onAction函式,以及context自己和store的dispatch。onAction主要是進行Effect處理。這邊還可以看到,進行context初始化的最後,還將自己的onAction包裝註冊到store的廣播中去,這樣就可以接收到別人發出的action廣播。
Component繼承自Logic
// redux_component/logic.dart
@override
Dispatch createDispatch(
OnAction onAction, Context<T> ctx, Dispatch parentDispatch) {
Dispatch dispatch = (Action action) {
throw Exception(
'Dispatching while appending your effect & onError to dispatch is not allowed.');
};
/// attach to store.dispatch
dispatch = _applyOnAction<T>(onAction, ctx)(
dispatch: (Action action) => dispatch(action),
getState: () => ctx.state,
)(parentDispatch);
return dispatch;
}
static Middleware<T> _applyOnAction<T>(OnAction onAction, Context<T> ctx) {
return ({Dispatch dispatch, Get<T> getState}) {
return (Dispatch next) {
return (Action action) {
final Object result = onAction?.call(action);
if (result != null && result != false) {
return;
}
//skip-lifecycle-actions
if (action.type is Lifecycle) {
return;
}
if (!shouldBeInterruptedBeforeReducer(action)) {
ctx.pageBroadcast(action);
}
next(action);
};
};
};
}
}
上面分發的邏輯大概可以透過上圖來表示
透過onAction將action交給component對應的effect進行處理
當effect無法處理此action,且此action非lifecycle-actions,且不需中斷則廣播給當前Page的其餘所有effects
最後就是繼續將action分發給store的dispatch(parentDispatch傳入的其實就是store.dispatch)
02 store中的dispatch
從store的建立程式碼我們可以看到store的dispatch的具體邏輯
// redux/create_store.dart
final Dispatch dispatch = (Action action) {
_throwIfNot(action != null, 'Expected the action to be non-null value.');
_throwIfNot(
action.type != null, 'Expected the action.type to be non-null value.');
_throwIfNot(!isDispatching, 'Reducers may not dispatch actions.');
try {
isDispatching = true;
state = reducer(state, action);
} finally {
isDispatching = false;
}
final List<_VoidCallback> _notifyListeners = listeners.toList(
growable: false,
);
for (_VoidCallback listener in _notifyListeners) {
listener();
}
notifyController.add(state);
};
store的dispatch過程比較簡單,主要就是進行reducer的呼叫,處理完成後通知監聽者。
03 middleware
Page繼承自Component,增加了middleware機制,fish-redux的redux部分本身其實就對middleware做了支援,可以透過StoreEnhancer的方式將middlewares進行組裝,合併到Store的dispatch函式中。
middleware機制可以允許我們透過中介軟體的方式對redux的state做AOP處理,比如fish-redux自帶的logMiddleware,可以對state的變化進行log,分別列印出state變化前和變化後的值。
當Page配置了middleware之後,在建立pageStore的過程中會將配置的middleware傳入,傳入之後會對store的dispath進行增強加工,將middleware的處理函式串聯到dispatch中。
// redux_component/component.dart
Widget buildPage(P param) {
return wrapper(_PageWidget<T>(
component: this,
storeBuilder: () => createPageStore<T>(
initState(param),
reducer,
applyMiddleware<T>(buildMiddleware(middleware)),
),
));
}
// redux_component/page_store.dart
PageStore<T> createPageStore<T>(T preloadedState, Reducer<T> reducer,
[StoreEnhancer<T> enhancer]) =>
_PageStore<T>(createStore(preloadedState, reducer, enhancer));
// redux/create_store.dart
Store<T> createStore<T>(T preloadedState, Reducer<T> reducer,
[StoreEnhancer<T> enhancer]) =>
enhancer != null
? enhancer(_createStore)(preloadedState, reducer)
: _createStore(preloadedState, reducer);
所以這裡可以看到,當傳入enhancer時,createStore的工作被enhancer代理了,會返回一個經過enhancer處理過的store。而PageStore建立的時候傳入的是中介軟體的enhancer。
// redux/apply_middleware.dart
StoreEnhancer<T> applyMiddleware<T>(List<Middleware<T>> middleware) {
return middleware == null || middleware.isEmpty
? null
: (StoreCreator<T> creator) => (T initState, Reducer<T> reducer) {
assert(middleware != null && middleware.isNotEmpty);
final Store<T> store = creator(initState, reducer);
final Dispatch initialValue = store.dispatch;
store.dispatch = (Action action) {
throw Exception(
'Dispatching while constructing your middleware is not allowed. '
'Other middleware would not be applied to this dispatch.');
};
store.dispatch = middleware
.map((Middleware<T> middleware) => middleware(
dispatch: (Action action) => store.dispatch(action),
getState: store.getState,
))
.fold(
initialValue,
(Dispatch previousValue,
Dispatch Function(Dispatch) element) =>
element(previousValue),
);
return store;
};
}
這裡的邏輯其實就是將所有的middleware的處理函式都串到store的dispatch,這樣當store進行dispatch的時候所有的中介軟體的處理函式也會被呼叫。下面為各個處理函式的執行順序,
首先還是component中的dispatch D1 會被執行,然後傳遞給store的dispatch,而此時store的dispatch已經經過中介軟體的增強,所以會執行中介軟體的處理函式,最終store的原始dispatch函式D2會被執行。
透過上面的內容,現在我們可以知道一個action是如何一步步的派送給effect,reducer去進行處理的,我們也可以透過middleware的方式去跟蹤state的變化,這樣的擴充套件性給框架本身帶來無限可能。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69900359/viewspace-2641585/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Redis 中的集合型別是怎麼實現的?Redis型別
- fish_redux 「食用指南」Redux
- Fish Redux 使用指南Redux
- 微信直播是怎麼實現的?
- fish_redux 使用指北(這可能是比官方更友好的文件)Redux
- JVM的ServerSocket是怎麼實現的(上)JVMServer
- JVM的ServerSocket是怎麼實現的(下)JVMServer
- v-model 是怎麼實現的?
- synchronized底層是怎麼實現的?synchronized
- 直播美顏SDK中的美白功能是怎麼實現的?
- Go 中的 channel 怎麼實現的?Go
- 【AliFlutter】Flutter Fish Redux 2.0 架構演進實踐FlutterRedux架構
- Angular 的依賴注入是怎麼實現的?Angular依賴注入
- 工業生產中的“主動剎車”,是怎麼實現的?
- 手把手入門Fish-Redux開發flutter(中)ReduxFlutter
- 和 koa 不同的 express 是怎麼實現Express
- 美顏SDK中的美顏功能是怎麼實現的?美顏SDK的工作原理是什麼?
- Flutter 入坑指南(dio +fish_redux)FlutterRedux
- 初識Fish Redux在Flutter中使用ReduxFlutter
- Flutter Fish Redux架構演進2.0FlutterRedux架構
- 【Redis面試題】Redis的字串是怎麼實現的?Redis面試題字串
- Broker的主從架構是怎麼實現的?架構
- SimpleJdonFrameworkTest實現的原理是怎麼樣的啊?Framework
- tag標籤是怎麼用OT實現的?
- [譯]Swift 3 中實現Dispatch once擴充套件Swift套件
- 在K8S中,是怎麼實現資料持久化的?K8S持久化
- Laravel 的 CSRF - 白名單底層是怎麼實現的Laravel
- APPLE WATCH 的呼吸動效是怎麼實現的?APP
- 請問ECLIPSE的DEBUG是怎麼實現的??Eclipse
- 軟體是現實世界的抽象,關鍵是怎麼抽?抽象
- Redux 是什麼Redux
- Go Error 巢狀到底是怎麼實現的?GoError巢狀
- Java虛擬機器是怎麼實現synchronized的Java虛擬機synchronized
- 淘寶客?CPS技術是怎麼實現的?
- 一個有趣的問題, 你知道SqlDataAdapter中的Fill是怎麼實現的嗎SQLLDAAPT
- d3-force怎麼使用?該演算法是怎麼實現的?演算法
- 背景透明的實現,直播電商原始碼是怎麼做的原始碼
- 請問Jive的緩衝機制是怎麼實現的?