至此,这已是探索 Flutter 状态管理方式文章的最后一篇,同时这也是新年后的第一篇文章,以后我将将他们应用在实际项目中开发并将值的学习的项目开源出来。对于其中讲解可能有点浅尝则止,由于给出的实例相对简单,但相信聪明的程序员都会有本身的学习方法,你能够从给出的实例结合本身的所学引深出更好的设计方法。git
同时要送给你们的建议是:请在须要这些状态管理方式时使用它,我见过很多的开发者都有用大刀砍白菜的意思,这并非一个好习惯,你会发现这些状态管理方式有时候不但不会使开发简单,其实还会加大代码量,使其变得复杂,对于如何选择,这里还不够说清楚,但愿大家都能找到本身的管理应用程序的方式。程序员
全部实例:github
github 地址:github.com/MeandNi/Flu…redux
Redux 由 Facebook 2015年提出,是基于 Flux 理念实现的一个响应式框架的状态管理方式,最先应用于 React 中,然后 React Native 、 Flutter 等多个框架也一样可使用。框架
学习 Redux 以前,请了解 Redux 所能作到的事情:less
若是你用过 React ,相信你对上面的概念已经很清晰了,没使用过?也 OK,下面慢慢道来....ide
总体的思路:全部状态存放在 store 中,Redux 将 store 内全部状态放入对应的组件中呈如今 Ui 上,用户与 UI 交互(如点击)发起一个 action(一个描述行为的对象),store 可判别 action类型并做用相应的 reducer(操做改变状态的纯函数),reducer 完成相应改变后将数据放到全局的 store 中,实现改变。模块化
思路简单,描述起来蛮复杂,其实它的目的就是实现代码做用域的分离。函数
那么如何让将以上描述应用于实际的应用程序中呢?学习
其中的实现与 ScopedModel 很类似,抓住两个要点,如何在 UI 中呈现以及如何 发起 action 改变状态。
咱们首先定义 一个全局状态 AppState:
@immutable
class AppState {
final counter;
AppState(this.counter);
}
复制代码
里面有一个 counter 变量用于计数。
如前面所述,State 的变化,会致使 UI 的变化。可是,用户接触不到 State,只能接触到 UI。因此,State 的变化必须是 UI 致使的。Action 就是 UI 发出的通知,表示 State 应该要发生变化了。
咱们这里有一个促使 counter 增长的 action:
enum Actions { Increment }
复制代码
Store 收到 Action 之后,必须给出一个新的 State,这样 View 才会发生变化。这种 State 的计算过程就叫作 Reducer。
Reducer 是一个函数,它接受 Action 和当前 State 做为参数,返回一个新的 State。
AppState reducer(AppState prev, action) {
if (action == Actions.Increment) {
return new AppState(prev.counter + 1);
}
return prev;
}
复制代码
reducer 中判断了 action 时 Increment 这一类型,将一个新的 AppState 返回到 store。
首先初始化状态:
final store = new Store(reducer, initialState: new AppState(0));
复制代码
而后显示状态:
new StoreConnector(
converter: (store) => store.state.counter,
builder: (context, counter) => new Text(
'$counter',
style: Theme.of(context).textTheme.display1,
),
)
复制代码
经过 converter 属性拿到 state 中的 counter 属性。
而后传入 builder 应用在组件中。
new StoreConnector(
converter: (store) {
return () => store.dispatch(Actions.Increment);
},
builder: (context, callback) => new FloatingActionButton(
onPressed: callback,
tooltip: 'Increment',
child: new Icon(Icons.add),
),
),
复制代码
一样是使用 StoreConnector,然而此次经过 converter 拿到的是一个 store.dispatch(Actions.Increment)
,store.dispatch()
是 View 发出 Action 的惟一方法。然后在组件中调用该回调方法便可。
完整代码被放在一个文件中:样例代码
Redux 应用在 ShoppingCart:样例代码
在复杂的应用中咱们能够将应用程序中的 reducer 根据业务类型分离,例如用户信息、产品信息等不一样业务的操做分离到单独的模块,
然后将其合并:
实现上看的分离后,又可只将相应业务的数据放到相应业务根 widget(其子组件的全部数据和操做来自该根组件)
咱们将须要的数据及操做到一个对象中,传递到组件中:
class DeviceFragment extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: new StoreConnector<AppState, _ViewModel>(
converter: _ViewModel.fromStore,
builder: (context, vm) {
return DeviceList(
devices: vm.devices,
onStateChanged: vm.onStateChanged,
onRemove: vm.onRemove,
onUndoRemove: vm.onUndoRemove,
);
}),
);
}
}
class _ViewModel {
final List<Device> devices;
// final bool loading;
final Function(Device) onStateChanged;
final Function(Device) onRemove;
final Function(Device) onUndoRemove;
_ViewModel({
@required this.devices,
// @required this.loading,
@required this.onStateChanged,
@required this.onRemove,
@required this.onUndoRemove,
});
static _ViewModel fromStore(Store<AppState> store) {
return _ViewModel(
devices: store.state.devices,
// loading: store.state.isLoading,
onStateChanged: (device) {
store.dispatch(editItem(device.copyWith(state: !device.state)));
},
onRemove: (device) {
store.dispatch(deleteDevice(device));
},
onUndoRemove: (device) {
store.dispatch(AddDeviceAction(device));
},
);
}
}
复制代码
这样使得产生模块化管理的思想!(以上实例来自正在开发的一个真实项目,目前还未开源。)
同时,在实际的应用程序中,你必定须要在程序启动初期来加载来自云端或者数据本地的数据,你能够在入口的页面中接受一个加载数据的函数,放入 initState 函数中。
博客地址:meandni.com/
Githib:github.com/MeandNi/
欢迎一块儿交流学习!