Fish Redux中的Dispatch是怎麼實現的?

零.前言

咱們在使用fish-redux構建應用的時候,界面代碼(view)和事件的處理邏輯(reducer,effect)是徹底解耦的,界面須要處理事件的時候將action分發給對應的事件處理邏輯去進行處理,而這個分發的過程就是下面要講的dispatch, 經過本篇的內容,你能夠更深入的理解一個action是如何一步步去進行分發的。git

一.從example開始

爲了更好的理解action的dispatch過程,咱們就先以todo_list_page中一條todo條目的勾選事件爲例,來看點擊後事件的傳遞過程,經過斷點debug咱們很容易就可以發現點擊時候發生的一切,具體過程以下:github

  1. 用戶點擊勾選框,GestureDetector的onTap會被回調
  2. 經過buildView傳入的dispatch函數對doneAction進行分發,發現todo_component的effect中沒法處理此doneAction,因此將其交給pageStore的dispatch繼續進行分發
  3. pageStore的dispatch會將action交給reducer進行處理,故doneAction對應的_markDone會被執行,對state進行clone,並修改clone後的state的狀態,而後將這個全新的state返回
  4. 而後pageStore的dispatch會通知全部的listeners,其中負責界面重繪的_viewUpdater發現state發生變化,通知界面進行重繪更新

二.Dispatch實現分析

Dispatch在實現的過程當中借鑑了Elm。redux

Dispatch在fish-redux中的定義以下app

typedef Dispatch = void Function(Action action);

本質上就是一個action的處理函數,接受一個action,而後對action進行分發。框架

下面我門經過源碼來進行詳細的分析ide

1.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廣播。ui

Component繼承自Logicthis

// 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);
        };
      };
    };
  }
}

上面分發的邏輯大概能夠經過上圖來表示spa

  1. 經過onAction將action交給component對應的effect進行處理
  2. 當effect沒法處理此action,且此action非lifecycle-actions,且不需中斷則廣播給當前Page的其他全部effects
  3. 最後就是繼續將action分發給store的dispatch(parentDispatch傳入的其實就是store.dispatch)

2. 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的調用,處理完成後通知監聽者。

3.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的變化,這樣的擴展性給框架自己帶來無限可能。

原文連接 本文爲雲棲社區原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索