有的大的背景前提,在公司做的业务开发用的是Hummer,Hummer并没有提供全局状态管理的工具类,在业务开发中,会产生很多逻辑附带数据的操作,为了避免业务逻辑与数据逻辑交织变得复杂,于是便有了移植类似的功能去Hummer上的想法;在移植前须知其工作原理,就从Flutter Redux入手了。
一、概念§
1.Store§
用来储存、管理全局的页面状态,将页面UI与存储在Store中的状态进行绑定,通过修改Store的状态达到UI自动更新的能力。
/// 创建一个Store
class CountState {
int count;
CountState(this.count);
factory CountState.init() {
return CountState(0);
}
}
final store = Store<CountState>(countReducer,
initialState: CountState.init(),
middleware: [middleware]);
Store
参数reducer、middleware,下面会提到。
参数initialState,去设置初始的状态。控制页面加载出来时的默认显示内容。
2.Reducer§
reducer本质上是一个函数。它会根据不同的动作指令,去修改调整状态值。
reducer具体定义:
typedef State Reducer<State>(State state, dynamic action);
其中,state是Store中存储的状态,action是特定的动作指令,最后返回一个更新后的状态。
/// 如何创建一个reducer
enum Action {
INCREMENT,
DECREMENT
}
CountState countReducer(CountState state, dynamic action) {
if (action == Action.INCREMENT) {
state.count += 1;
}
if (action == Action.DECREMENT) {
state.count -= 1;
}
return state;
}
3.Middleware§
中间件,作用域位于reducer更新状态之前。本质上也是一个函数。
具体定义:
typedef void Middleware<State>(Store<State> store,dynamic action,NextDispatcher next);
其中,前两个参数与reducer参数一致。next是调用下一个中间件的函数。
middleware(Store<CountState> store, dynamic action, NextDispatcher next) {
if (action == Action.INCREMENT || action == Action.DECREMENT) {
...
}
//调用下一个中间件
next(action);
}
4.StoreProvider§
Store的提供者,本质是Widget。一般包裹在根部Widget, 给整个Widget Tree 提供Store。
如何使用StoreProvider:
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return StoreProvider<CountState>(store: store,
child: ...);
}
}
StoreProvider
5.StoreConnector§
StoreConnector也是一个Widget,通过它可以连接到StoreProvider存储的状态。用它来包裹局部Widget, 并将Store.state与Widget绑定。
如何创建一个StoreConnector:
class _MyHomePageState extends State<MyHomePage> {
Widget build(BuildContext context) {
return StoreConnector<CountState, int>(
converter: (state) => state.state.count,
builder: (context, count) {
return //...;
},
);
}
}
StoreConnector<T,ViewModel>中T指Store中存储的状态类型,ViewModel指本Widget需要的状态类型(上面的例子中int就是需要的状态类型)。
T->ViewModel要如何转换呢?
在创建StoreConnector时需要一个入参converter, 它就是负责这个转换逻辑的。它也是一个函数,具体定义:
typedef StoreConverter<S, ViewModel> = ViewModel Function(
Store<S> store,
);
final StoreConverter<S, ViewModel> converter;
6.Dispatcher§
如何通知状态更新呢?通过store.dispatch:
StoreProvider.of<CountState>(context).dispatch(Action.INCREMENT);
//或者如果能拿到 Store 的话
store.dispatch(Action.INCREMENT)
StoreProvider.of
二、Redux页面更新流程§

三、实现原理§
Redux将state与页面UI绑定,通过更新State来更新页面。若页面有多处UI与同一状态值有关联,修改状态能够达到牵一发而动全身的效果。越是复杂的页面,越能体现出Redux的优势。
那Redux是如何实现UI自更新的呢?是通过常用的setState方法吗?dispatch action会导致所有组件都刷新吗?
///Store的部分源码
class Store<State> {
Reducer<State> reducer;
//通过它来传递状态的
final StreamController<State> _changeController;
State _state;
List<NextDispatcher> _dispatchers;
Store(
this.reducer, {
State initialState,
List<Middleware<State>> middleware = const [],//中间件
bool syncStream: false,
bool distinct: false,//若是true,`reducer`返回的state与current state相等的话,流程就停止。见方法_createReduceAndNotify
})
: _changeController = new StreamController.broadcast(sync: syncStream) {
_state = initialState;
_dispatchers = _createDispatchers(
middleware,
_createReduceAndNotify(distinct),
);//这里可以看出,是middleware先运行,最后是reducer
}
Stream<State> get onChange => _changeController.stream;
//将reducer包装成NextDispatcher
NextDispatcher _createReduceAndNotify(bool distinct) {
return (dynamic action) {
final state = reducer(_state, action);
//distinct为true且前后状态一样,直接return
if (distinct && state == _state) return;
_state = state;
//将新的状态添加到stream中
_changeController.add(state);
};
}
List<NextDispatcher> _createDispatchers(
List<Middleware<State>> middleware,
NextDispatcher reduceAndNotify,
) {
final dispatchers = <NextDispatcher>[]..add(reduceAndNotify);
// Convert each [Middleware] into a [NextDispatcher]
for (var nextMiddleware in middleware.reversed) {
final next = dispatchers.last;
dispatchers.add(
(dynamic action) => nextMiddleware(this, action, next),
);
}
return dispatchers.reversed.toList();
}
//dispach action之后,依次运行middleware,最后运行reducer
void dispatch(dynamic action) {
_dispatchers[0](action);
}
}
在发起store.dispatch后,会依次运行middleware,最后运行reducer。并且,会将new state添加到_changeController中。Store的工作到这里就结束了,好像看不出是哪里通知了子视图刷新的。往下看StoreConnector.
///StoreConnector的部分源码
class StoreConnector<S, ViewModel> extends StatelessWidget {
//...
StoreConnector({
Key key,
this.builder,
this.converter,
this.distinct = false,
this.onInit,
this.onDispose,
this.rebuildOnChange = true,
this.ignoreChange,
this.onWillChange,
this.onDidChange,
this.onInitialBuild,
}) : assert(builder != null),
assert(converter != null),
super(key: key);
Widget build(BuildContext context) {
return _StoreStreamListener<S, ViewModel>(
store: StoreProvider.of<S>(context),
builder: builder,
converter: converter,
distinct: distinct,
onInit: onInit,
onDispose: onDispose,
rebuildOnChange: rebuildOnChange,
ignoreChange: ignoreChange,
onWillChange: onWillChange,
onDidChange: onDidChange,
onInitialBuild: onInitialBuild,
);
}
}
/// _StoreStreamListener源码
class _StoreStreamListener<S, ViewModel> extends StatefulWidget {
//...
_StoreStreamListener({
Key key,
this.builder,
this.store,
this.converter,
this.distinct = false,
this.onInit,
this.onDispose,
this.rebuildOnChange = true,
this.ignoreChange,
this.onWillChange,
this.onDidChange,
this.onInitialBuild,
}) : super(key: key);
}
/// 最后到了_StoreStreamListener,源码
class _StoreStreamListenerState<S, ViewModel>
extends State<_StoreStreamListener<S, ViewModel>> {
Stream<ViewModel> stream;
ViewModel latestValue;
void initState() {
_init();
super.initState();
}
void _init() {
if (widget.onInit != null) {
widget.onInit(widget.store);
}
//将原state转成需要使用的状态类型
latestValue = widget.converter(widget.store);
if (widget.onInitialBuild != null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
widget.onInitialBuild(latestValue);
});
}
//这就是Store中_changeController的流。跟Store的状态联系了起来。
var _stream = widget.store.onChange;
//将状态流经过一系列的变形过滤
if (widget.ignoreChange != null) {
_stream = _stream.where((state) => !widget.ignoreChange(state));
}
stream = _stream.map((_) => widget.converter(widget.store));
//如果设置了distinct标识符,若前后两转换值一致的话,就丢弃。通过它可达到组件只关注与之有关的状态变化。不用任何的状态过来都去刷新。
if (widget.distinct) {
stream = stream.where((vm) {
final isDistinct = vm != latestValue;
return isDistinct;
});
}
stream =
stream.transform(StreamTransformer.fromHandlers(handleData: (vm, sink) {
latestValue = vm;
if (widget.onWillChange != null) {
widget.onWillChange(latestValue);
}
if (widget.onDidChange != null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
widget.onDidChange(latestValue);
});
}
sink.add(vm);
}));
}
Widget build(BuildContext context) {
//StoreConnector.rebuildOnChange的默认值是true。所以,最后是使用了StreamBuilder包裹子Widget,且将stream传入其中。
return widget..rebuildOnChange
? StreamBuilder<ViewModel>(
stream: stream,
builder: (context, snapshot) => widget.builder(
context,
snapshot.hasData ? snapshot.data : latestValue,
),
)
: widget.builder(context, latestValue);
}
}
StreamBuilder接收一个Stream,一旦Stream中有新的状态过来,就会重新build返回新的widget。而这个Stream是经过store.onchange(store._changeController.stream)变换过来的。