Flutter 状态管理(二)——fish redux源码解析及思考

简介

之前我们横向比较了 fish reduxflutter redux以及provider的用法。本文主要以fish redux为例介绍一下其更新机制,以及设计思想。

提出问题

1、fish redux的更新和setState是否有关系?
2、setState到底是全局更新还是局部更新?
3、effect 和 reducer 到底有何区别,谁先执行?

设计方案介绍

首先,我们已知fish redux的用法,关键的对象为effect、reducer、component、connector、page、adapter、View和state、store等。
之前详细介绍过,现在简单说一下个人对着6个角色的理解:
注册表相关:
Adapter:类比于Android 列表中的adapter,注册每种type对应的view
page:相当于页面的注册表文件,用于配置相关的内容
component:组件,类似于Android 的Fragment或者更小粒度的自定义View

逻辑处理:
effect:用于处理相关的数据,有些情况也会进行功能的中转。类似于MVP模式中的P层
reducer:类似于MVVM中的VM,进行数据更新后页面通知

页面处理
state:用于定义页面中的数据内容,当发起reducer处理后,如果两个state不相同则更新页面
view:可以当做是flutter原生中的build方法,返回对应的页面内容

连接器
connector:一个页面注册表文件的注册,可能需要使用到其他的注册表文件,但当前只有自己可用的state,这时候就需要创建一个connector去协助转换。

具体实现

dispatch的触发过程简单介绍一下具体实现。
先看一下现象,我们在页面中触发一个onRefresh的事件分发,

//view
dispatch(HouseListPageActionCreator.onRefresh())

之后effect会马上得到响应,

//effect
Effect<HouseListPageState> buildEffect() {
  return combineEffects(<Object, Effect<HouseListPageState>>{
    HouseListPageAction.onRefresh: _onRefresh
  });
}

void _onRefresh(Action action, Context<HouseListPageState> ctx) {
  //do somethings
  ctx.dispatch(HouseActionCreator.pageRefresh(state));
}

然后又发起了一个pageRefresh事件,然后reducer马上得到了响应。

//reducer
Reducer<HouseListPageState> buildReducer() {
  return asReducer(<Object, Reducer<HouseListPageState>>{
    HouseAction.pageRefresh: _pageRefresh
  });
}

HouseListPageState _pageRefresh(HouseListPageState state, Action action) {
  HouseListPageState state = action.payload;
  return state.clone();
}

之后发现页面进行了数据更新。

通过以上流程我们可以设想一下,如果我们设计要怎么做这件事。

1、Page创建时,记录effect和reducer注册的key和闭包value
2、创建成功后,使用命令模式,包装并暴露一个Dispatch,当有地方调用dispatch时命令模式响应,执行查找对应的key,找到闭包value并执行。
3、执行完成后,判断是否需要更新进行更新,这时候需要个需要更新的条件。明显fish redux选择的是如果当前state和老state不相同则进行更新。

到此,还有个问题,为什么effect和reducer都是通过dispatch执行的,却只有reducer才会更新页面呢?

下面我们看看具体的代码实现,是否和我们的猜测相同:

1、Page创建

class HouseListPage
    extends Page<HouseListPageState, Map<String, dynamic>> {
  HouseListPage()
      : super(
          initState: initState,
          effect: buildEffect(),
          reducer: buildReducer(),
          view: buildView,
          dependencies: Dependencies<HouseListPageState>(
              adapter: NoneConn<HouseListPageState>() +
                  HouseListAdapter(),
              slots: <String, Dependent<HouseListPageState>>{}),
          middleware: <Middleware<HouseListPageState>>[],
        );
}

可以看到,初始化时使用的是initState和buildView的闭包,以及effect和reducer的对象。这样处理的原因是因为state和view的初始化是要使用参数的。

///page的实现
abstract class Page<T, P> extends Component<T> {
  /// AppBus is a event-bus used to communicate between pages.
  final DispatchBus appBus = sharedBus;

  final InitState<T, P> _initState;

  final Enhancer<T> enhancer;

  /// connect with other stores
  final List<StoreUpdater<T>> _storeUpdaters = <StoreUpdater<T>>[];

  Page({
    @required InitState<T, P> initState,
    @required ViewBuilder<T> view,
    Reducer<T> reducer,
    ReducerFilter<T> filter,
    Effect<T> effect,
    Dependencies<T> dependencies,
    ShouldUpdate<T> shouldUpdate,
    WidgetWrapper wrapper,

    /// implement [StateKey] in T instead of using key in Logic.
    /// class T implements StateKey {
    ///   Object _key = UniqueKey();
    ///   Object key() => _key;
    /// }
    @deprecated Key Function(T) key,
    List<Middleware<T>> middleware,
    List<ViewMiddleware<T>> viewMiddleware,
    List<EffectMiddleware<T>> effectMiddleware,
    List<AdapterMiddleware<T>> adapterMiddleware,
  })  : assert(initState != null),
        _initState = initState,
        enhancer = EnhancerDefault<T>(
          middleware: middleware,
          viewMiddleware: viewMiddleware,
          effectMiddleware: effectMiddleware,
          adapterMiddleware: adapterMiddleware,
        ),
        super(
          view: view,
          dependencies: dependencies,
          reducer: reducer,
          filter: filter,
          effect: effect,
          shouldUpdate: shouldUpdate,
          wrapper: wrapper,
          // ignore:deprecated_member_use_from_same_package
          key: key,
        );

  Widget buildPage(P param) => protectedWrapper(_PageWidget<T, P>(
        page: this,
        param: param,
      ));

  Store<T> createStore(P param) => updateStore(createBatchStore<T>(
        _initState(param),
        reducer,
        storeEnhancer: enhancer.storeEnhance,
      ));

  Store<T> updateStore(Store<T> store) => _storeUpdaters.fold(
        store,
        (Store<T> previousValue, StoreUpdater<T> element) =>
            element(previousValue),
      );

  /// page-store connect with app-store
  void connectExtraStore<K>(
    Store<K> extraStore,

    /// To solve Reducer<Object> is neither a subtype nor a supertype of Reducer<T> issue.
    Object Function(Object, K) update,
  ) =>
      _storeUpdaters.add((Store<T> store) => connectStores<Object, K>(
            store,
            extraStore,
            update,
          ));

  DispatchBus createPageBus() => DispatchBusDefault();
}

可见_initState是page独有的,其他effect,reducer等,都是到component中去处理。这个的_initState最终应该是在StatefulWidget的initState中调用的。

再接着分析一下Component:

Component({
    @required ViewBuilder<T> view,
    Reducer<T> reducer,
    ReducerFilter<T> filter,
    Effect<T> effect,
    Dependencies<T> dependencies,
    ShouldUpdate<T> shouldUpdate,
    WidgetWrapper wrapper,

    /// implement [StateKey] in T instead of using key in Logic.
    /// class T implements StateKey {
    ///   Object _key = UniqueKey();
    ///   Object key() => _key;
    /// }
    @deprecated Key Function(T) key,
    bool clearOnDependenciesChanged = false,
  })  : assert(view != null),
        _view = view,
        _wrapper = wrapper ?? _wrapperByDefault,
        _shouldUpdate = shouldUpdate ?? updateByDefault<T>(),
        _clearOnDependenciesChanged = clearOnDependenciesChanged,
        super(
          reducer: reducer,
          filter: filter,
          effect: effect,
          dependencies: dependencies,
          // ignore:deprecated_member_use_from_same_package
          key: key,
        );

可见view是在component层返回并处理的,可见component的有个很重要的职责是页面处理。

Component又继承了Logic进行了能力的封装,这里可以看到的是装饰器模式,但是个人感觉这个地方继承不如依赖,因为logic逻辑处理应该只是Component组件的一个能力。

我们还是根据刚才的线索,先分析Dispatch之后Logic是如何处理的。

Logic({
    Reducer<T> reducer,
    Dependencies<T> dependencies,
    ReducerFilter<T> filter,
    Effect<T> effect,

    /// implement [StateKey] in T instead of using key in Logic.
    /// class T implements StateKey {
    ///   Object _key = UniqueKey();
    ///   Object key() => _key;
    /// }
    @deprecated Object Function(T state) key,
  })  : _reducer = reducer,
        _filter = filter,
        _effect = effect,
        _dependencies = dependencies?.trim(),
        // ignore:deprecated_member_use_from_same_package
        assert(isAssignFrom<T, StateKey>() == false || key == null,
            'Implements [StateKey] in T instead of using key in Logic.'),
        _key = isAssignFrom<T, StateKey>()
            // ignore:avoid_as
            ? ((T state) => (state as StateKey).key())
            // ignore:deprecated_member_use_from_same_package
            : key;

初始化时记录了effect和reducer对象。


至此初始化完成了,我们得到了一个page。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uw9xangd-1617870092282)(evernotecid://666BE8A9-6339-4218-8620-6B5866F0B229/appyinxiangcom/21627020/ENResource/p820)]


2、Widget的创建

Page最终要展示,都要落实到Widget上
Page:

Page.buildWidget(p)
Widget buildPage(P param) => protectedWrapper(_PageWidget<T, P>(
        page: this,
        param: param,
      ));

_PageWidget最后返回的就是对应的要展示的状态Widget:

class _PageWidget<T, P> extends StatefulWidget {
  final Page<T, P> page;
  final P param;

  const _PageWidget({
    Key key,
    @required this.page,
    @required this.param,
  }) : super(key: key);

  @override
  State<StatefulWidget> createState() => _PageState<T, P>();
}

class _PageState<T, P> extends State<_PageWidget<T, P>> {
  Store<T> _store;
  DispatchBus _pageBus;

  final Map<String, Object> extra = <String, Object>{};

  @override
  void initState() {
    super.initState();
    _store = widget.page.createStore(widget.param);
    _pageBus = widget.page.createPageBus();
  }

  @override
  Widget build(BuildContext context) {
    return widget.page.buildComponent(
      _store,
      _store.getState,
      bus: _pageBus,
      enhancer: widget.page.enhancer,
    );
  }
  
  ……
}

这里的initState有个关键的createStore方法,这里就会执行我们之前提到的page注册时传入的_initState的闭包。

Store<T> createStore(P param) => updateStore(createBatchStore<T>(
        _initState(param),
        reducer,
        storeEnhancer: enhancer.storeEnhance,
      ));

创建好的store,将在state的build方法,传递给Component,并创建Component

@override
  Widget buildComponent(
    Store<Object> store,
    Get<Object> getter, {
    @required DispatchBus bus,
    @required Enhancer<Object> enhancer,
  }) {
    /// Check bus: DispatchBusDefault(); enhancer: EnhancerDefault<Object>();
    assert(bus != null && enhancer != null);

    return protectedWrapper(
      isPureView()
          ? _PureViewWidget<T>(
              store: store,
              viewBuilder: enhancer.viewEnhance(protectedView, this, store),
              getter: getter,
              bus: bus,
            )
          : ComponentWidget<T>(
              component: this,
              getter: _asGetter<T>(getter),
              store: store,
              key: key(getter()),
              bus: bus,
              enhancer: enhancer,
            ),
    );
  }

这里我们不是PureView,则直接返回ComponentWidget

class ComponentWidget<T> extends StatefulWidget {
  ///这里的createState最后创建的就是ComponentState
  @override
  ComponentState<T> createState() => component.createState();
}

class ComponentState<T> extends State<ComponentWidget<T>> {
  ComponentContext<T> _ctx;

  ComponentContext<T> get ctx => _ctx;

  @mustCallSuper
  @override
  Widget build(BuildContext context) => _ctx.buildWidget();

  @mustCallSuper
  @override
  void initState() {
    super.initState();

    /// init context
    _ctx = widget.component.createContext(
      widget.store,
      context,
      () => widget.getter(),
      markNeedsBuild: () {
        if (mounted) {
          setState(() {});
        }
      },
      bus: widget.bus,
      enhancer: widget.enhancer,
    );

    /// register store.subscribe
    _ctx.registerOnDisposed(widget.store.subscribe(() => _ctx.onNotify()));

    _ctx.onLifecycle(LifecycleCreator.initState());
  }
}

同样返回的就是一个StatefulWidget,还是关注一下重点的initState方法。这里创建了一个Context对象,这个上下文对象是fish redux处理数据的核心,后续处理Action的流程重点解析。

build方法,返回_ctx.buildWidget();

  ///context.dart
  @override
  Widget buildWidget() {
    Widget result = _widgetCache;
    if (result == null) {
      result = _widgetCache = view(state, dispatch, this);

      dispatch(LifecycleCreator.build(name));
    }
    return result;
  }

这里的view(state, dispatch, this),就是buildView的方法,state就是initState创建的内容,dispatch稍候我们分析,viewService就是当前生成的Context。

至此,Widget创建完成,页面就展示出来了。


3、事件处理

fish reduxComponentContext创建开始分析。

ComponentContext({
    @required AbstractComponent<T> logic,
    @required Store<Object> store,
    @required BuildContext buildContext,
    @required Get<T> getState,
    @required this.view,
    @required this.shouldUpdate,
    @required this.name,
    @required this.markNeedsBuild,
    @required this.sidecarCtx,
    @required DispatchBus bus,
    @required Enhancer<Object> enhancer,
  })  : assert(bus != null && enhancer != null),
        super(
          logic: logic,
          store: store,
          buildContext: buildContext,
          getState: getState,
          bus: bus,
          enhancer: enhancer,
        ) {
    _latestState = state;

    sidecarCtx?.setParent(this);
  }

最终会调用super(LogicContext的初始化),

LogicContext({
    @required this.logic,
    @required this.store,
    @required BuildContext buildContext,
    @required this.getState,

    /// pageBus
    @required this.bus,
    @required this.enhancer,
  })  : assert(logic != null),
        assert(store != null),
        assert(buildContext != null),
        assert(getState != null),
        assert(bus != null && enhancer != null),
        _buildContext = buildContext {
    ///
    _effectDispatch = logic.createEffectDispatch(this, enhancer);

    /// create Dispatch
    _dispatch = logic.createDispatch(
      _effectDispatch,
      logic.createNextDispatch(
        this,
        enhancer,
      ),
      this,
    );

    /// Register inter-component broadcast
    registerOnDisposed(bus.registerReceiver(_effectDispatch));
  }

OK,现在我们看到了_dispatch,这个对象将是ctx.dispatch对应的那个对象,他用来分发及处理事件。

这里的Logic就是Component对象,之后调用其createEffectDispatchcreateDispatch方法,这里是控制反转原则,创建Dispatch交给上层控制,控制权在context中。

logic:

@override
  Dispatch createEffectDispatch(ContextSys<T> ctx, Enhancer<Object> enhancer) {
    return helper.createEffectDispatch<T>(

        /// enhance userEffect
        enhancer.effectEnhance(
          protectedEffect,
          this,
          ctx.store,
        ),
        ctx);
  }
  
  @override
  Dispatch createNextDispatch(ContextSys<T> ctx, Enhancer<Object> enhancer) =>
      helper.createNextDispatch<T>(ctx);
  
  @override
  Dispatch createDispatch(
    Dispatch effectDispatch,
    Dispatch nextDispatch,
    Context<T> ctx,
  ) =>
      helper.createDispatch<T>(effectDispatch, nextDispatch, ctx);

可以看到,这里的创建做了一层代理,hepler才是真正的实现类。

hepler.dart

/// return [EffectDispatch]
Dispatch createEffectDispatch<T>(Effect<T> userEffect, Context<T> ctx) {
  return (Action action) {
    final Object result = userEffect?.call(action, ctx);

    //skip-lifecycle-actions
    if (action.type is Lifecycle && (result == null || result == false)) {
      return _SUB_EFFECT_RETURN_NULL;
    }

    return result;
  };
}

/// return [NextDispatch]
Dispatch createNextDispatch<T>(ContextSys<T> ctx) => (Action action) {
      ctx.broadcastEffect(action, excluded: true);
      ctx.store.dispatch(action);
    };

/// return [Dispatch]
Dispatch createDispatch<T>(Dispatch onEffect, Dispatch next, Context<T> ctx) =>
    (Action action) {
      final Object result = onEffect?.call(action);
      if (result == null || result == false) {
        next(action);
      }

      return result == _SUB_EFFECT_RETURN_NULL ? null : result;
    };

这三个对象返回的都是(action)=>{}的function对象,下面来分析最终是怎么拼接成_dispatch的。

createEffectDispatch的两个参数,effect和ctx,

  @override
  Effect<K> effectEnhance<K>(
    Effect<K> effect,
    AbstractLogic<K> logic,
    Store<T> store,
  ) =>
      _effectEnhancer?.call(logic, store)?.call(_inverterEffect<K>(effect)) ??
      effect;

因为我们没有添加增强因子enhancer,所以第一个参数就是我们创建时传入的effect对象。由此可知logic.createEffectDispatch返回的就是一个effect根据action执行的闭包。

createNextDispatch返回的也是一个action执行的闭包。这个闭包是先执行ctx.broadcastEffect然后执行ctx.store.dispatch。通过名字猜测,这两个方法一个是执行其他effect,一个是执行store的action。具体分析一下,首先ctx.store是什么?

///Page.dart
Store<T> createStore(P param) => updateStore(createBatchStore<T>(
        _initState(param),
        reducer,
        storeEnhancer: enhancer.storeEnhance,
      ));

这里就有两个很重要的参数,一个是我们传进来的initState一个是reducer,可见这两个参数组合成了store,看看具体的createBatchStore

最终在create_store.dart中找到了真正的store的创建。

Store<T> _createStore<T>(final T preloadedState, final Reducer<T> reducer) {
  _throwIfNot(
    preloadedState != null,
    'Expected the preloadedState to be non-null value.',
  );

  final List<_VoidCallback> _listeners = <_VoidCallback>[];
  final StreamController<T> _notifyController =
      StreamController<T>.broadcast(sync: true);

  T _state = preloadedState;
  Reducer<T> _reducer = reducer ?? _noop<T>();
  bool _isDispatching = false;
  bool _isDisposed = false;

  return Store<T>()
    ..getState = (() => _state)
    ..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.');

      if (_isDisposed) {
        return;
      }

      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);
    }
    ..replaceReducer = (Reducer<T> replaceReducer) {
      _reducer = replaceReducer ?? _noop;
    }
    ……
}

这里便是store的生成,并且也看到了ctx.store.dispatch究竟是何物。

至此,事件发起的逻辑已经基本清晰,由createDispatch可知,ctx._dispatch()是dispatch最开始执行的地方,先执行effect.call再执行next,这里加了一个条件,如果是生命周期的action将不执行next方法。 其中next方法会执行到ctx.store.dispatch从而执行reducer方法。

现在 事件发起到effect或reducer的处理过程已经明晰,下面我们剩下一个问题,何时刷新,如何刷新


4、刷新机制

从之前的分析我们首先得到,非生命周期effect返回的是null,reducer返回的是state,都是经过dispatch去做事件处理的。我们正常使用fish redux时知道,reducer在返回不同于原数据的state时,会触发更新,那么这个更新机制是如何触发的呢?

如果这个功能是我们自己实现,确定了reducer用如上方案后,还需要解决那几个问题呢?
1、怎么找到要更新的widget
2、局部更新还是全部更新
3、原State的数据怎么处理

下面接着分析下源码:
从reducer执行后开始:

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

dispatch只做了两件事,一件是遍历_notifyListeners并执行,第二件是将reducer返回的state放入到_notifyController中。OK,_notifyListeners_notifyController在之前_createStore的代码中都能发现其赋值的内容。

final List<_VoidCallback> _listeners = <_VoidCallback>[];
  final StreamController<T> _notifyController =
      StreamController<T>.broadcast(sync: true);

那么响应的内容就是listner()broadcast()的执行。

Listeners又是在哪里添加监听者的呢,这个能力是store向外提供了一个subscribe方法,提供给外层去注册对应的响应,注册用的是模板方法模式,响应用的是广播。(这里很容易联想到RxJava的实现,可以简单做一个类比,发现RxJava在实现上更现实命令模式,当不注册subscribe时observable是不执行的)。

    ..subscribe = (_VoidCallback listener) {
      _throwIfNot(
        listener != null,
        'Expected the listener to be non-null value.',
      );
      _throwIfNot(
        !_isDispatching,
        'You may not call store.subscribe() while the reducer is executing.',
      );

      _listeners.add(listener);

      return () {
        _throwIfNot(
          !_isDispatching,
          'You may not unsubscribe from a store listener while the reducer is executing.',
        );
        _listeners.remove(listener);
      };
    }
    ..observable = (() => _notifyController.stream)

具体的调用方:

_BatchStore(Store<T> store) : assert(store != null) {
    ……

    setupBatch();
  }
  
  void setupBatch() {
    if (!_isSetupBatch) {
      _isSetupBatch = true;
      super.subscribe(_batch);

      subscribe = (void Function() callback) {
        assert(callback != null);
        _listeners.add(callback);
        return () {
          _listeners.remove(callback);
        };
      };
    }
  }

最终判断state已经是否更新将在这个方法中执行。

///batch_store.dart
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)) {
        _prevState = curState;

        final List<void Function()> notifyListeners = _listeners.toList(
          growable: false,
        );
        for (void Function() listener in notifyListeners) {
          listener();
        }

        _isBatching = false;
      }
    }
  }

当前还是在Store中的,是Store的一个mixin的类,所以里面的方法最终会调用的是store中的方法,例如getState等。
由此,getState返回的是最新的State,判断如果两个State不相等则遍历并执行_listeners。

这时候的_listener,又是谁呢?

这里的处理其实是做了一层隔离,setupBatch()调用时,重新为subscribe赋值,方法如下:

subscribe = (void Function() callback) {
        assert(callback != null);
        _listeners.add(callback);
        return () {
          _listeners.remove(callback);
        };
      };

也就是外层调用的store.subscribe(callback)最终会加入子类的_listener中,父类的listener触发仅会影响子类的_batch方法触发。

我们此时再回到Component的initState中,这里很容易就找到了store.subcribe的注册,每次component初始化生成View时就会将()->_ctx.notify()闭包传递到subscribe中,这也就是对应的触发机制了。

_ctx.registerOnDisposed(widget.store.subscribe(() => _ctx.onNotify()))

再来看看_ctx.notify的实现

  @override
  void onNotify() {
    final T now = state;
    if (shouldUpdate(_latestState, now)) {
      _widgetCache = null;

      markNeedsBuild();

      _latestState = now;
    }
  }

shouldUpdate默认是判断两个state是否相等。当然这个shoudUpdate也对外暴露了,可以在component初始化时进行配置。

static ShouldUpdate<K> updateByDefault<K>() =>
      (K _, K __) => !identical(_, __);

markNeedsBuild

      markNeedsBuild: () {
        if (mounted) {
          setState(() {});
        }
      }

OK,总结一下,dispatch发起事件响应后,先执行effect,如果不是证明周期事件,并且返回值是null或者false,再执行reducer,reducer在处理完成后遍历并执行所有的监听,如果新旧状态不相同则遍历并执行所有的component的ctx的更新,component的ctx此时在判断各自状态是否有变化,然后执行setState方法。

在这里插入图片描述


4、页面更新

setState触发后,widget的didUpdateWidget响应,

  void didUpdateWidget() {
    final T now = state;
    if (shouldUpdate(_latestState, now)) {
      _widgetCache = null;
      _latestState = now;
    }
  }

将缓存清空。然后执行build方法

  @override
  Widget buildWidget() {
    Widget result = _widgetCache;
    if (result == null) {
      result = _widgetCache = view(state, dispatch, this);

      dispatch(LifecycleCreator.build(name));
    }
    return result;
  }

创建了新的widget。

回溯前面的问题,fish redux其实是局部更新,当component的state当次没有发生改变时则不进行更新而是使用缓存。

5、销毁

_ctx.registerOnDisposed(widget.store.subscribe(() => _ctx.onNotify()))

widget在dispose时会主调用ctx.dispose,store创建时最后会返回一个闭包,专门用于remove对应的listener

..subscribe = (_VoidCallback listener) {
      _throwIfNot(
        listener != null,
        'Expected the listener to be non-null value.',
      );
      _throwIfNot(
        !_isDispatching,
        'You may not call store.subscribe() while the reducer is executing.',
      );

      _listeners.add(listener);

      return () {
        _throwIfNot(
          !_isDispatching,
          'You may not unsubscribe from a store listener while the reducer is executing.',
        );
        _listeners.remove(listener);
      };
    }

解决问题

1、fish redux的更新和setState是否有关系?
最终的更新就是落到setState上。

2、fish redux到底是全局更新还是局部更新?
局部更新(也可以说是全局更新,但是state不变的地方返回的是缓存的widget)

3、effect 和 reducer 到底有何区别,谁先执行?
effect限制性,reducer后执行。
每个页面初始化时会生成一个store,reducer是store的一个重要属性,用于控制页面更新等操作。component在initState时会将自己的notify放到store的listners中,实现监听的调用。

另外:
ctx.store是页面级别的,它包含着所有的dependences的reducer,effect是通过bus也实现了全局的影响,也就是说,只要effect或者reducer对应的component还存在,就能拿到对应的影响。

思考与总结

1、销毁的这个方式很棒,模板方法模式。将销毁的方法返回到处理器中统一管理。
2、最终的更新落到了setState上,这个地方是不是可以替换成Provider的方式,这样好像可以替换状态对比等。
3、模板方法模式使用很多,可以严格控制业务代码结构,适合于大型APP开发。

个人感觉,一开始应该是为了代码分层,约束开发人员代码书写方式。将代码类似MVP的方式进行了分层,之后又将P分解成了effect和reducer,reducer是用来更新页面的,从而产生了store的概念。之后根据redux的思想,设计了view reducer action这套内容,最终实现了现在的fish redux

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值