简介
之前我们横向比较了 fish redux
、flutter 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 redux
的ComponentContext
创建开始分析。
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对象,之后调用其createEffectDispatch
和createDispatch
方法,这里是控制反转原则,创建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
。