Fish-Redux 研究

由于目前的项目采用bloc方式构建,对于的复杂页面的交互处理起来代码量越来越庞大,比如带抽屉效果的地图页面,涉及到20多个bloc之间的状态传值,而bloc的很多state的转换都依赖于widget构建,对于日益庞大的widget tree,嵌套式的bloc相互订阅,不管是从新功能开发和bug的修复都非常的不方便, 从github相关评论和用户使用量来看,Fish-Redux的设计原则和UI数据逻辑分治的核心思想,应该比较适合目前项目中的一些复杂场景,于是决定深入研究一下.原文https://github.com/alibaba/fish-redux

流程图

主要类关系图

工程目录如下

├── redux
│   ├── apply_middleware.dart
│   ├── basic.dart
│   ├── combine_reducers.dart
│   ├── connector.dart
│   ├── create_store.dart
│   └── redux.dart
├── redux_adapter
│   ├── adapter.dart
│   ├── dynamic_flow_adapter.dart
│   ├── recycle_context.dart
│   ├── redux_adapter.dart
│   ├── source_flow_adapter.dart
│   └── static_flow_adapter.dart
├── redux_aop
│   ├── aop.dart
│   ├── common_aop
│   └── redux_aop.dart
├── redux_component
│   ├── auto_dispose.dart
│   ├── basic.dart
│   ├── batch_store.dart
│   ├── component.dart
│   ├── context.dart
│   ├── dependencies.dart
│   ├── dependent.dart
│   ├── dispatch_bus.dart
│   ├── enhancer.dart
│   ├── helper.dart
│   ├── lifecycle.dart
│   ├── local.dart
│   ├── logic.dart
│   ├── page.dart
│   └── redux_component.dart
├── redux_component_mixin
│   ├── keep_alive_mixin.dart
│   ├── private_reducer_mixin.dart
│   ├── redux_component_mixin.dart
│   ├── single_ticker_provider_mixin.dart
│   ├── ticker_provider_mixin.dart
│   ├── visible_change_mixin.dart
│   └── widgets_binding_observer_mixin.dart
├── redux_connector
│   ├── connector.dart
│   ├── generator.dart
│   ├── map_like.dart
│   ├── none.dart
│   ├── op_mixin.dart
│   ├── redux_connector.dart
│   └── reselect.dart
├── redux_middleware
│   ├── adapter_middleware
│   ├── middleware
│   ├── redux_middleware.dart
│   └── view_middleware
├── redux_routes
│   ├── page_routes.dart
│   └── redux_routes.dart
└── utils
    ├── collections.dart
    ├── debug.dart
    ├── hash.dart
    ├── tuple.dart
    └── utils.dart

在项目创建之初试了下demo,对比bloc状态和概念较多,综合考虑项目的各种因数采用了bloc,如果要将其应用到项目复杂的场景,目前还需要再细细评味下源码.

Redux->basic.dart

此类包含了fish-redux最基本的概念,和基础类

  • Action: 行为事件,通常由UI界面或者某些后台服务发出,通常也称为意图, 通常在传递Action时会互带parameters作为当前传递的数据,类似Bloc中定义的Event

    class Action {
    const Action(this.type, {this.payload});
    final Object type;
    final dynamic payload;
    }
  • Reducer: 定义了怎样修改传入的数据,它的定义如下,有两个参数,本次传入的Action和当前的State,它会返回一个新的State, 其实现逻辑有点类似Bloc中的mapEventToState方法(此方法在Bloc内部实现,所以在内部也能直接获取到Bloc)

    `Reducer<T> = T Function(T state, Action action);`
    
  • Dispatch: 定义了怎么放松一个Action意图

    typedef Dispatch = dynamic Function(Action action);
    

基于Redux衍生出的一些其它的概念

  • Connector: 两个Object之间的连接的桥梁,其实就是定义了一个State怎么转换成为另外一个State类型,类比Bloc中的实现,Bloc中主要是通过Event传递数据再进行转换,此处相当于mapEventToState进一步细化

    abstract class AbstractConnector<S, P> {
    P get(S state); 
    SubReducer<S> subReducer(Reducer<P> reducer);
    }
  • SubReducer: 一个函数用于修改部分data的函数, 对比Reducer可以看出它多一个参数isStateCopied,用于性能优化

    typedef SubReducer<T> = T Function(T state, Action action, bool isStateCopied);
    

其它概念-事件订阅

  • Subscribe: 输入订阅并可以通过Result结束订阅,功能类似StreamSubscriptionlisten的组合

    typedef Subscribe = void Function() Function(void Function() callback);
    
  • Store: 数据存储,用于存储State

    typedef StoreCreator<T> = Store<T> Function(
    T preloadedState,
    Reducer<T> reducer,
    );
    • 从它的定义来看,它存储了Redux交互过程层中的关键对象,持有当前Redux上下文信息,姑且可以把它理解为Bloc实力本身吧. dart class Store<T> {
      Get<T> getState;
      Dispatch dispatch;
      Subscribe subscribe;
      Observable<T> observable;
      ReplaceReducer<T> replaceReducer;
      Future<dynamic> Function() teardown;
      }
      小结: redux/basic.dart主要定义了basic的概念,和一些轻量级的函数

中间件
- Middleware: 中间件,返回一个可以合成的Dispatch
```dart
typedef Middleware = Composable Function({
Dispatch dispatch,
Get getState,
});
typedef StoreCreator = Store Function(
T preloadedState,
Reducer reducer,
);
typedef StoreEnhancer = StoreCreator Function(StoreCreator creator);

  ```

Redux->apply_middleware.dart

  • 插入中间,主要作用于Dispatch过程 dart StoreEnhancer<T> applyMiddleware<T>(List<Middleware<T>> middleware) {

Redux->combine_reducers.dart

此类主要负责redux的action和state事件的合并处理,以及Reducer的转换

  • combineSubReducers
  • combineReducers
  • castReducer

Redux->connector.dart

  • state转换
abstract class ImmutableConn<T, P> implements AbstractConnector<T, P> { ...
abstract class MutableConn<T, P> implements AbstractConnector<T, P> { ...

Redux->create_store.dart

  • 创建Store
Store<T> _createStore<T>(final T preloadedState, final Reducer<T> reducer) {
/// 1. 初始化 `preloadedState`必须为非空状态,Store至少要有一个State
/// 2. 创建一个`List<_VoidCallback> _listeners`,用于保存监听者 (subscribe1)
/// 3. 用于同步传递一个State的流,这样其他组件可以通过Stream订阅当前Store的State是否变更
final StreamController<T> _notifyController =
      StreamController<T>.broadcast(sync: true);
/// 4. 事件Action的派发过程监控,action执行完毕才能之后后一个
     try {
        _isDispatching = true;
        _state = _reducer(_state, action);
      } finally {
        _isDispatching = false;
      }
/// 5. 订阅是事件回调用 (subscribe2)
      for (_VoidCallback listener in _notifyListeners) {
        listener();
      }
/// 6. 可选择性的替换Reduer,更加灵活,相当Bloc对于于同一个Event每次map时执行的方法不一样,默认不做处理
       ..replaceReducer = (Reducer<T> replaceReducer) {
      _reducer = replaceReducer ?? _noop;
    }
/// 7. 添加订阅者,所以subscribe的返回值执行能移除订阅者,这样通过`Subscribe`可以为Store添加多个订阅者  (subscribe3),
    ..subscribe = (_VoidCallback listener) { ...
      _listeners.add(listener); ...
      return () { ...
        _listeners.remove(listener);
      };
/// 8. 添加Observer事件流的订阅,和subscribe功能大致相同,没有太多的断言限制
     ..observable = (() => _notifyController.stream)
/// 9. 销毁Store的订阅者
      ..teardown = () {
      _isDisposed = true;
      _listeners.clear();
      return _notifyController.close();
    };
  • 创建增强版的Store,主要是为了应用中间件
Store<T> createStore<T>(T preloadedState, Reducer<T> reducer,
        [StoreEnhancer<T> enhancer]) =>
    enhancer != null
        ? enhancer(_createStore)(preloadedState, reducer)
        : _createStore(preloadedState, reducer);

redux_component->basic.dart

  • ViewBuilder: 返回一个Widget,用于提供渲染户界面的的配置信息,Dispatch则是用于发送事件,该事件会经过reducer,在Reducer进行相应的逻辑处理
typedef ViewBuilder<T> = Widget Function(
  T state,
  Dispatch dispatch,
  ViewService viewService,
);
  • ListBuildAdapter: 主要用户配置ListView.builder,改善页面滑动性能
class ListAdapter {
  final int itemCount;
  final IndexedWidgetBuilder itemBuilder;
  const ListAdapter(this.itemBuilder, this.itemCount);
}
  • AdapterBuilder: 配置ListAdapter一起使用
typedef AdapterBuilder<T> = ListAdapter Function(
  T state,
  Dispatch dispatch,
  ViewService viewService,
);
  • ViewUpdater: 驱动UI的数据源,决定视图的创建和更新时机
abstract class ViewUpdater<T> {
  Widget buildWidget();
  void didUpdateWidget();
  void onNotify();
  void forceUpdate();
  void clearCache();
}
  • ShouldUpdate: 控制component刷新
typedef ShouldUpdate<T> = bool Function(T old, T now);
  • ExtraData: 除了State之外,在上下文中配置一些全局的信息
abstract class ExtraData {
  /// Get|Set extra data in context if needed.
  Map<String, Object> get extra;
}

///1. ViewService: 提供Component
abstract class ViewService implements ExtraData { ...
  ListAdapter buildAdapter();
  ///配置其他组件,动态获取
  Widget buildComponent(String name, {Widget defaultWidget});
  /// ViewService的寄居的Widget所对应的Context
  BuildContext get context;
  /// 发送action事件给其他的接受者
  void broadcast(Action action); 
}

///2. Context
abstract class Context<T> extends AutoDispose implements ExtraData {
  /// Get the latest state
  T get state;

  /// The way to send action, which will be consumed by self, or by broadcast-module and store.
  dynamic dispatch(Action action);

  /// Get BuildContext from the host-widget
  BuildContext get context;
 
  /// 用来传递 `Component`组件 `mixin`属性,如tickerProvider
  State get stfState; 
  
  Widget buildComponent(String name); 
  void broadcast(Action action); 
  void broadcastEffect(Action action, {bool excluded}); 
  void Function() addObservable(Subscribe observable); 
  void forceUpdate(); 
  void Function() listen({
    bool Function(T, T) isChanged,
    void Function() onChange,
  });
}
  • ContextSys: 提供系统相关的上下文信息
abstract class ContextSys<T> extends Context<T> implements ViewService { 
  void onLifecycle(Action action);  //相应系统的lifeCycle事件
  void bindForceUpdate(void Function() forceUpdate); 
  Store<dynamic> get store; 
  Enhancer<dynamic> get enhancer; 
  DispatchBus get bus;
}
  • Dependent
abstract class Dependent<T> {
  Get<Object> subGetter(Get<T> getter);

  SubReducer<T> createSubReducer();

  Widget buildComponent(
    Store<Object> store,
    Get<T> getter, {
    @required DispatchBus bus,
    @required Enhancer<Object> enhancer,
  });

  /// P state
  ListAdapter buildAdapter(ContextSys<Object> ctx);

  ContextSys<Object> createContext(
    Store<Object> store,
    BuildContext buildContext,
    Get<T> getState, {
    @required DispatchBus bus,
    @required Enhancer<Object> enhancer,
  });

  bool isComponent(); 
  bool isAdapter();
}
  • Dependent: 依赖的抽象程,根据此类的定义主要有两种依赖,一种是适配器依赖,用于对List进行适配的依赖,另外一种是用于构建新的Component
abstract class Dependent<T> {
  Get<Object> subGetter(Get<T> getter);

  SubReducer<T> createSubReducer();

  Widget buildComponent(
    Store<Object> store,
    Get<T> getter, {
    @required DispatchBus bus,
    @required Enhancer<Object> enhancer,
  });

  /// P state
  ListAdapter buildAdapter(ContextSys<Object> ctx);

  ContextSys<Object> createContext(
    Store<Object> store,
    BuildContext buildContext,
    Get<T> getState, {
    @required DispatchBus bus,
    @required Enhancer<Object> enhancer,
  });

  bool isComponent();

  bool isAdapter();
}
  • AbstractLogic: 名字代表它的功能,封装component的逻辑,主要包括两类逻辑` Reducer & SideEffect.
abstract class AbstractLogic<T> {
  Reducer<T> get reducer; 
  /// State适配
  Object onReducer(Object state, Action action);
  /// Dispatch事件适配 
  Dispatch createEffectDispatch(ContextSys<T> ctx, Enhancer<Object> enhancer);  
  Dispatch createNextDispatch(ContextSys<T> ctx, Enhancer<Object> enhancer);  
  Dispatch createDispatch(
    Dispatch effectDispatch,
    Dispatch nextDispatch,
    ContextSys<T> ctx,
  ); 
  /// 系统上下文
  ContextSys<T> createContext(
    Store<Object> store,
    BuildContext buildContext,
    Get<T> getState, {
    @required DispatchBus bus,
    @required Enhancer<Object> enhancer,
  });

  /// 为当前的逻辑对象设定key,用于复用
  Object key(T state);
  /// 从slot找查找对应的依赖
  Dependent<T> slot(String name);
  /// 获取一个适配器依赖 adapter Dependent
  Dependent<T> adapterDep(); 
  Type get propertyType;
}

/// 基于Component的抽象逻辑协议,`AbstractComponent`定义了它的用户视图窗口的配置信息
abstract class AbstractComponent<T> implements AbstractLogic<T> {
  Widget buildComponent(
    Store<Object> store,
    Get<T> getter, {
    @required DispatchBus bus,
    @required Enhancer<Object> enhancer,
  });
}

redux_component->auto_dispose.dart

  • AutoDispose: 自动释放,根据咸鱼的文档描述,它是一个轻量级的生命周期管理对象

    • 当这个继承于AutoDispose的对象被释放时,释放它的所有Child,断开和Parent之间的联系,触发OnDispose的回调事件
    • 通过_FieldsParentChild进行关联

      class _Fields {
      bool isDisposed = false;
      Set<AutoDispose> children;
      AutoDispose parent;
      void Function() onDisposed;
      }
    • 通过visit来实现对上下游想关联的对象遍历操作,和flutter framework中的widget更新时采用visit方式类似,通过visitvisitor方法,利用多态的特性,接耦操作

    • dispose:

      void dispose() { ...
      for (AutoDispose child in copy) { ...
    child.dispose();
    _fields.parent?._fields?.children?.remove(this); ...
    _fields.onDisposed?.call(); ...
    _fields.isDisposed = true;
    }
    • onDisposed
     void onDisposed(void Function() onDisposed) {
    assert(_fields.onDisposed == null);
    if (_fields.isDisposed) {
    onDisposed?.call();
    } else {
    _fields.onDisposed = onDisposed;
    }
    }
    AutoDispose registerOnDisposed(void Function() onDisposed)

redux_component->batch_store.dart

  • Store的基础上再次进行封装,对Store的订阅事件进行默认的批处理绑定
  • 监听来自engine每一帧绘制完成的回调,批量的传递给store的每个订阅者
class _BatchStore<T> extends Store<T> with _BatchNotify<T> {
  _BatchStore(Store<T> store) : assert(store != null) {
    getState = store.getState;
    subscribe = store.subscribe;
    replaceReducer = store.replaceReducer;
    dispatch = store.dispatch;
    observable = store.observable;
    teardown = store.teardown;
    //初始化的时候绑定所有listen的人订阅事件
    setupBatch();
  }
}
mixin _BatchNotify<T> on Store<T> {
  final List<void Function()> _listeners = <void Function()>[];
  bool _isBatching = false;
  bool _isSetupBatch = false;
  T _prevState;

  void setupBatch() { ...
  ///1. 外部的所有订阅事件通过`_batch`方法进行默认绑定
      super.subscribe(_batch); 
      subscribe = (void Function() callback) { ...
        _listeners.add(callback);
        return () {
          _listeners.remove(callback);
        };
      };
    }
  }
  /// 界面更新时间回调注册,条件过滤,
  bool isInSuitablePhase() {
    return SchedulerBinding.instance != null &&
        SchedulerBinding.instance.schedulerPhase !=
            SchedulerPhase.persistentCallbacks &&
        !(SchedulerBinding.instance.schedulerPhase == SchedulerPhase.idle &&
            WidgetsBinding.instance.renderViewElement == null);
  }
  
  /// 2. 批处理页面的刷新事件回调
  void _batch() {
    if (!isInSuitablePhase()) {
      if (!_isBatching) {
        _isBatching = true;
        SchedulerBinding.instance.addPostFrameCallback((Duration duration) {
          if (_isBatching) {
            _batch(); ...
    } else {
      final T curState = getState();
      if (!identical(_prevState, curState)) { ...
        for (void Function() listener in notifyListeners) {
          listener();
        } 
        _isBatching = false; 
  • 连接连个Store,代码上看主要是一个Store订阅了另外一个Store的State

    Store<T> connectStores<T, K>(
      Store<T> mainStore,
    Store<K> extraStore,
    T Function(T, K) update,
    ) {
    /// 1. 注册state的更新事件
    final void Function() subscriber = () {
    final T prevT = mainStore.getState();
    final T nextT = update(prevT, extraStore.getState());
    if (nextT != null && !identical(prevT, nextT)) {
    mainStore.dispatch(Action(_UpdateState.Assign, payload: nextT));
    }
    };
    /// 2. 绑定另外一个store的state变更事件,因为state变更时,会通知它的listener
    final void Function() unsubscribe = extraStore.subscribe(subscriber);
    ///3. 订阅另外一个store,接收地一个state
    subscriber();
    ///4. 取消另一个store的订阅并释放当前的store资源
    final Future<dynamic> Function() superMainTD = mainStore.teardown;
    mainStore.teardown = () {
    unsubscribe?.call();
    return superMainTD();
    };
    return mainStore;
    }

redux_component->component.dart

  • 定义了页面构成的基本元素,也是用户界面的入口
  • 通过Component来提供一个widget,基于Component和它的widget创建以及销毁,可以分为:

    initState,
    didChangeDependencies,
    build,
    reassemble,
    didUpdateWidget,
    deactivate,
    dispose,
  • 基于ListView循环复用的小部件Widget,如Cell,Card,ListItem又增加了2个状态appeardisappear

  • Component它作为一个Widget的提供者,通过lifeCycle触发了系列的事件绑定,通过logic的层层抽象,将不同的逻辑分散到不同的抽象层中,处理不同的业务逻辑,以Commpnent为中心

  • 测试Demo: https://gitee.com/jiodg45/study_fish_redux.git

Tips

  • 订阅事件多采用了 Function() action(Function listener)加内置listeners数组,来实现订阅和解除订阅的操作。
 void Function() registerReceiver(Dispatch dispatch) {
    assert(!_dispatchList.contains(dispatch),
        'Do not register a dispatch which is already existed');

    if (dispatch != null) {
      _dispatchList.add(dispatch);
      return () {
        _dispatchList.remove(dispatch);
      };
    } else {
      return null;
    }
  }
  • context中的widget缓存
class ComponentState<T> extends State<ComponentWidget<T>> { ...
  Widget buildWidget() {
    Widget result = _widgetCache;
    if (result == null) {
      result = _widgetCache = view(state, dispatch, this);

      dispatch(LifecycleCreator.build(name));
    }
    return result;
  }
  • helper.dartReduceEnhancer系列因子进行了大量的reduce,merge,combine操作,在框架内部自动的对分散的逻辑进行集中管理

  • 在widget之间的关系处理上利用DependenciesDependent进行连接,通过Connector来传递不同state的数据. 如下是一次基本的执行过程

posted @ 2020-10-29 00:55  阿甘左  阅读(245)  评论(0编辑  收藏  举报