Fish Redux中的Dispatch是怎么实现的?

前言

开源地址:https://github.com/alibaba/fish-redux

我们在使用fish-redux构建应用的时候,界面代码(view)和事件的处理逻辑(reducer,effect)是完全解耦的,界面需要处理事件的时候将action分发给对应的事件处理逻辑去进行处理,而这个分发的过程就是下面要讲的dispatch, 通过本篇的内容,你可以更深刻的理解一个action是如何一步步去进行分发的。

从example开始

为了更好的理解action的dispatch过程,我们就先以todolistpage中一条todo条目的勾选事件为例,来看点击后事件的传递过程,通过断点debug我们很容易就能够发现点击时候发生的一切,具体过程如下:

  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在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的初始化

 
 
  1. // redux_component/context.dart DefaultContext初始化方法


  2.  DefaultContext({

  3.    @required this.factors,

  4.    @required this.store,

  5.    @required BuildContext buildContext,

  6.    @required this.getState,

  7.  })  : assert(factors != null),

  8.        assert(store != null),

  9.        assert(buildContext != null),

  10.        assert(getState != null),

  11.        _buildContext = buildContext {

  12.    final OnAction onAction = factors.createHandlerOnAction(this);


  13.    /// create Dispatch

  14.    _dispatch = factors.createDispatch(onAction, this, store.dispatch);


  15.    /// Register inter-component broadcast

  16.    _onBroadcast =

  17.        factors.createHandlerOnBroadcast(onAction, this, store.dispatch);

  18.    registerOnDisposed(store.registerReceiver(_onBroadcast));

  19.  }

context中的dispatch是通过factors来进行创建的,factors其实就是当前component,factors创建dispatch的时候传入了onAction函数,以及context自己和store的dispatch。onAction主要是进行Effect处理。这边还可以看到,进行context初始化的最后,还将自己的onAction包装注册到store的广播中去,这样就可以接收到别人发出的action广播。

Component继承自Logic

 
 
  1. // redux_component/logic.dart


  2.  @override

  3.  Dispatch createDispatch(

  4.      OnAction onAction, Context<T> ctx, Dispatch parentDispatch) {

  5.    Dispatch dispatch = (Action action) {

  6.      throw Exception(

  7.          'Dispatching while appending your effect & onError to dispatch is not allowed.');

  8.    };


  9.    /// attach to store.dispatch

  10.    dispatch = _applyOnAction<T>(onAction, ctx)(

  11.      dispatch: (Action action) => dispatch(action),

  12.      getState: () => ctx.state,

  13.    )(parentDispatch);

  14.    return dispatch;

  15.  }


  16.    static Middleware<T> _applyOnAction<T>(OnAction onAction, Context<T> ctx) {

  17.    return ({Dispatch dispatch, Get<T> getState}) {

  18.      return (Dispatch next) {

  19.        return (Action action) {

  20.          final Object result = onAction?.call(action);

  21.          if (result != null && result != false) {

  22.            return;

  23.          }


  24.          //skip-lifecycle-actions

  25.          if (action.type is Lifecycle) {

  26.            return;

  27.          }



  28.          if (!shouldBeInterruptedBeforeReducer(action)) {

  29.            ctx.pageBroadcast(action);

  30.          }


  31.          next(action);

  32.        };

  33.      };

  34.    };

  35.  }

  36. }

bb

上面分发的逻辑大概可以通过上图来表示

  1. 通过onAction将action交给component对应的effect进行处理

  2. 当effect无法处理此action,且此action非lifecycle-actions,且不需中断则广播给当前Page的其余所有effects

  3. 最后就是继续将action分发给store的dispatch(parentDispatch传入的其实就是store.dispatch)

02   store中的dispatch

从store的创建代码我们可以看到store的dispatch的具体逻辑

 
 
  1. // redux/create_store.dart


  2.  final Dispatch dispatch = (Action action) {

  3.    _throwIfNot(action != null, 'Expected the action to be non-null value.');

  4.    _throwIfNot(

  5.        action.type != null, 'Expected the action.type to be non-null value.');

  6.    _throwIfNot(!isDispatching, 'Reducers may not dispatch actions.');


  7.    try {

  8.      isDispatching = true;

  9.      state = reducer(state, action);

  10.    } finally {

  11.      isDispatching = false;

  12.    }


  13.    final List<_VoidCallback> _notifyListeners = listeners.toList(

  14.      growable: false,

  15.    );

  16.    for (_VoidCallback listener in _notifyListeners) {

  17.      listener();

  18.    }


  19.    notifyController.add(state);

  20.  };

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中。

 
 
  1. // redux_component/component.dart


  2.  Widget buildPage(P param) {

  3.    return wrapper(_PageWidget<T>(

  4.      component: this,

  5.      storeBuilder: () => createPageStore<T>(

  6.            initState(param),

  7.            reducer,

  8.            applyMiddleware<T>(buildMiddleware(middleware)),

  9.          ),

  10.    ));

  11.  }


  12. // redux_component/page_store.dart


  13. PageStore<T> createPageStore<T>(T preloadedState, Reducer<T> reducer,

  14.        [StoreEnhancer<T> enhancer]) =>

  15.    _PageStore<T>(createStore(preloadedState, reducer, enhancer));


  16. // redux/create_store.dart


  17. Store<T> createStore<T>(T preloadedState, Reducer<T> reducer,

  18.        [StoreEnhancer<T> enhancer]) =>

  19.    enhancer != null

  20.        ? enhancer(_createStore)(preloadedState, reducer)

  21.        : _createStore(preloadedState, reducer);

所以这里可以看到,当传入enhancer时,createStore的工作被enhancer代理了,会返回一个经过enhancer处理过的store。而PageStore创建的时候传入的是中间件的enhancer。

 
 
  1. // redux/apply_middleware.dart


  2. StoreEnhancer<T> applyMiddleware<T>(List<Middleware<T>> middleware) {

  3.  return middleware == null || middleware.isEmpty

  4.      ? null

  5.      : (StoreCreator<T> creator) => (T initState, Reducer<T> reducer) {

  6.            assert(middleware != null && middleware.isNotEmpty);


  7.            final Store<T> store = creator(initState, reducer);

  8.            final Dispatch initialValue = store.dispatch;

  9.            store.dispatch = (Action action) {

  10.              throw Exception(

  11.                  'Dispatching while constructing your middleware is not allowed. '

  12.                  'Other middleware would not be applied to this dispatch.');

  13.            };

  14.            store.dispatch = middleware

  15.                .map((Middleware<T> middleware) => middleware(

  16.                      dispatch: (Action action) => store.dispatch(action),

  17.                      getState: store.getState,

  18.                    ))

  19.                .fold(

  20.                  initialValue,

  21.                  (Dispatch previousValue,

  22.                          Dispatch Function(Dispatch) element) =>

  23.                      element(previousValue),

  24.                );


  25.            return store;

  26.          };

  27. }

这里的逻辑其实就是将所有的middleware的处理函数都串到store的dispatch,这样当store进行dispatch的时候所有的中间件的处理函数也会被调用。下面为各个处理函数的执行顺序,

bb

首先还是component中的dispatch D1 会被执行,然后传递给store的dispatch,而此时store的dispatch已经经过中间件的增强,所以会执行中间件的处理函数,最终store的原始dispatch函数D2会被执行。

总结

通过上面的内容,现在我们可以知道一个action是如何一步步的派送给effect,reducer去进行处理的,我们也可以通过middleware的方式去跟踪state的变化,这样的扩展性给框架本身带来无限可能。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/69900359/viewspace-2641585/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/69900359/viewspace-2641585/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值