Flutter是Google(全球顶级互联网科技公司)出品,后台够硬,毫无疑问Flutter即将或已经成为跨平台开发的主流,Flutter野心很大,不仅冲击着原生开发,而且很有可能会烧到Web前端。作为移动端开发者的你,如果不关注Flutter的话,实在说不过去啦!
Flutter状态管理(Redux)flutter_redux的应用
什么时候不需要Redux,什么时候需要Redux
如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加复杂性。
1.用户的使用方式非常简单
2.用户之间没有协作
3.不需要与服务器大量交互,也没有使用 WebSocket
4.视图层(View)只从单一来源获取数据
上面这些情况,都不需要使用 Redux。
1.用户的使用方式复杂
2.不同身份的用户有不同的使用方式(比如普通用户和管理员)
3.多个用户之间可以协作
4.与服务器大量交互
5.View要从多个来源获取数据
上面这些情况才是 Redux 的适用场景:多交互、多数据源。
从组件角度看,如果你的应用有以下场景,可以考虑使用 Redux。
1.某个组件的状态,需要共享
2.某个状态需要在任何地方都可以拿到
3.一个组件需要改变全局状态
4.一个组件需要改变另一个组件的状态
发生上面情况时,如果不使用 Redux 或者其他状态管理工具,不按照一定规律处理状态的读写,代码很快就会变成一团乱麻。你需要一种机制,可以在同一个地方查询状态、改变状态、传播状态的变化。
总之,不要把 Redux 当作万灵丹,如果你的应用没那么复杂,就没必要用它。另一方面,Redux 只是 状态管理的一种解决方案,也可以选择其他方案。
如:Provider
一、效果图
点击按钮发起一个Redux Action更新界面(即更新State)
2、Flutter中集成flutter_redux
在pubspec.yaml文件中添加flutter_redux,当前版本1.1.0:
flutter_redux: ^0.5.3
2、创建用户实体
class User{
var name;
User(this.name);
void setName(String name) {
this.name = name;
}
String get getName => this.name;
// 命名构造函数
User.empty();
}
3、创建State(YDCState)
(1) Store对象包含所有数据。如果想得到某个时点的数据,就要对 Store 生成快照。这种时点的数据集合,就叫做 State。
(2) Redux 规定, 一个 State 对应一个 View。只要 State 相同,View 就相同。你知道 State,就知道 View 是什么样,反之亦然。
import 'package:ydcflutter_app/test/bean/User.dart';
import 'package:ydcflutter_app/redux/user_redux.dart';
///全局Redux store 的对象,保存State数据
class YDCState {
///用户信息
User user;
///构造方法
YDCState({this.user});
}
4、创建Action
(1) State 的变化,会导致 View 的变化。但是,用户接触不到 State,只能接触到 View。所以,State 的变化必须是 View 导致的。Action 就是 View 发出的通知,表示 State 应该要发生变化了。
(2) Action 描述当前发生的事情。改变 State 的唯一办法,就是使用 Action。它会运送数据到 Store。
/// 如果有 UpdateUserAction 发起一个请求时
/// 就会调用到 _updateLoaded
/// _updateLoaded 这里接受一个新的userInfo,并返回
User _updateLoaded(User user, action) {
user = action.user;
return user;
}
///定一个 UpdateUserAction ,用于发起 userInfo 的的改变
///类名随你喜欢定义,只要通过上面TypedReducer绑定就好
class UpdateUserAction {
final User user;
UpdateUserAction(this.user);
}
5、创建reducer
(1) Store 收到 Action 以后,必须给出一个新的 State,这样 View 才会发生变化。这种 State 的计算过程就叫做 Reducer。
(2) redux 的 combineReducers, 通过 TypedReducer 将 UpdateUserAction 与 reducers 关联起来
(3) Reducer 是一个函数,它接受 Action 和当前 State 作为参数,返回一个新的 State。
///创建 Reducer
///源码中 Reducer 是一个方法 typedef State Reducer(State state, dynamic action);
///我们自定义了 appReducer 用于创建 store
YDCState appReducer(YDCState state, action) {
return YDCState(
///通过自定义 UserReducer 将 YDCState 内的 userInfo 和 action 关联在一起
user: UserReducer(state.user, action),
);
}
final UserReducer = combineReducers([
TypedReducer(_updateLoaded),
]);
以上几个步骤代码都在YDCState和user_redux.dart中
YDCState代码如下:
import 'package:ydcflutter_app/test/bean/User.dart';
import 'package:ydcflutter_app/redux/user_redux.dart';
///全局Redux store 的对象,保存State数据
class YDCState {
///用户信息
User user;
///构造方法
YDCState({this.user});
}
///创建 Reducer
///源码中 Reducer 是一个方法 typedef State Reducer(State state, dynamic action);
///我们自定义了 appReducer 用于创建 store
YDCState appReducer(YDCState state, action) {
return YDCState(
///通过自定义 UserReducer 将 YDCState 内的 userInfo 和 action 关联在一起
user: UserReducer(state.user, action),
);
}
user_redux.dart代码如下:
import 'package:redux/redux.dart';
import 'package:ydcflutter_app/test/bean/User.dart';
/**
* 用户相关Redux
*/
/// redux 的 combineReducers, 通过 TypedReducer 将 UpdateUserAction 与 reducers 关联起来
final UserReducer = combineReducers([
TypedReducer(_updateLoaded),
]);
/// 如果有 UpdateUserAction 发起一个请求时
/// 就会调用到 _updateLoaded
/// _updateLoaded 这里接受一个新的userInfo,并返回
User _updateLoaded(User user, action) {
user = action.user;
return user;
}
///定一个 UpdateUserAction ,用于发起 userInfo 的的改变
///类名随你喜欢定义,只要通过上面TypedReducer绑定就好
class UpdateUserAction {
final User user;
UpdateUserAction(this.user);
}
6、创建store
(1 ) Store 就是保存数据的地方,你可以把它看成一个容器。整个应用只能有一个 Store。
(2) Store接收一个reducer,以及初始化State,我们想用Redux管理全局的状态的话,需要将store储存在应用的入口才行。而在应用打开时要先初始化一次应用的状态。所以在State中添加一个初始化的函数。
/// 创建Store,引用 YDCState 中的 appReducer 创建 Reducer
/// initialState 初始化 State
final store = new Store(
appReducer,
initialState: new YDCState(
user: User(""),
));
7、将Store放入顶层
flutter_redux提供了一个很棒的widget叫做StoreProvider,它的用法也很简单,接收一个store,和child Widget。
main文件全部源码:
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:ydcflutter_app/login/LoginPage.dart';
import 'package:ydcflutter_app/common/test/CartModel.dart';
import 'package:ydcflutter_app/common/test/Item.dart';
import 'package:provider/provider.dart';
import 'package:ydcflutter_app/test/bean/YDCState.dart';
import 'package:ydcflutter_app/test/bean/User.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';
//
//void main() => runApp( ChangeNotifierProvider.value(
// value: new CartModel("格子衬衫"),
// child:new YDCApp()));
void main() => runApp( new YDCApp());
final ThemeData kIOSTheme = new ThemeData(
primarySwatch: Colors.orange,
primaryColor: Colors.grey[100],
primaryColorBrightness: Brightness.light,
);
final ThemeData kDefaultTheme = new ThemeData(
primarySwatch: Colors.purple,
accentColor: Colors.orangeAccent[400],
);
class YDCApp extends StatelessWidget {
/// 创建Store,引用 YDCState 中的 appReducer 创建 Reducer
/// initialState 初始化 State
final store = new Store(
appReducer,
initialState: new YDCState(
user: User(""),
));
YDCApp({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
/// 通过 StoreProvider Widget 应用 store
return new StoreProvider(
store: store,
child:new MaterialApp(
// title: '谈天说地',
// theme: defaultTargetPlatform == TargetPlatform.iOS
// ? kIOSTheme
// : kDefaultTheme,
theme: new ThemeData(
primarySwatch: Colors.blue,
primaryColor: Colors.grey[50],
scaffoldBackgroundColor: Colors.grey[50],
dialogBackgroundColor: Colors.grey[50],
primaryColorBrightness: Brightness.light,
buttonColor: Colors.blue,
iconTheme: new IconThemeData(
color: Colors.grey[700],
),
hintColor: Colors.grey[400],
),
title: '纸聊',
// supportedLocales: [
// const Locale('zh', 'CH'),
// const Locale('en', 'US'),
// ],
home: new LoginPage(),
));
}
}
8、在子页面中获取Store中的state
通过StoreConnector获取store,S代表我们需要从store中获取什么类型的state,ViewModel指的是我们使用这个State时的实际类型。此时能够监听state发生变化时rebuilt Widget。
@override
Widget build(BuildContext context) {
///通过 StoreConnector 关联 YDCState 中的 User
return new StoreConnector(
///通过 converter 将 YDCState 中的 userInfo返回
converter: (store) => store.state.user,
///在 userInfo 中返回实际渲染的控件
builder: (context, userInfo) {
return new Scaffold( body:Center(
child: Builder(builder: (context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Builder(builder: (context) {
return Text("使用Redux更新数据: ${userInfo.name}");
}),
new Padding(
padding: const EdgeInsets.only(top: 15.0),
child:
StoreConnector(
converter: (store) {
var newUserInfo=User("把用户名字更新为无用");
return () => store.dispatch(new UpdateUserAction(newUserInfo));
},
builder: (context, callback) {
return FloatingActionButton(
onPressed: callback,
child: Icon(Icons.add),
);
},
)
),
],
);
}),
),
);
},
);
}
9、使用 store.dispatch发出action
store.dispatch()是 View 发出 Action 的唯一方法。
new Padding(
padding: const EdgeInsets.only(top: 15.0),
child:
StoreConnector(
converter: (store) {
var newUserInfo=User("把用户名字更新为无用");
return () => store.dispatch(new UpdateUserAction(newUserInfo));
},
builder: (context, callback) {
return FloatingActionButton(
onPressed: callback,
child: Icon(Icons.add),
);
},
)
),
store.dispatch接受一个 Action 对象作为参数,将它发送出去。
TestReduxPage全部代码:
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';
import 'package:ydcflutter_app/redux/user_redux.dart';
import 'package:ydcflutter_app/test/bean/User.dart';
import 'package:ydcflutter_app/test/bean/YDCState.dart';
class TestReduxPage extends StatefulWidget {
@override
State createState() => new _TestReduxPageState();
}
class _TestReduxPageState extends State {
BuildContext mContext;
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
///通过 StoreConnector 关联 YDCState 中的 User
return new StoreConnector(
///通过 converter 将 YDCState 中的 userInfo返回
converter: (store) => store.state.user,
///在 userInfo 中返回实际渲染的控件
builder: (context, userInfo) {
return new Scaffold( body:Center(
child: Builder(builder: (context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Builder(builder: (context) {
return Text("使用Redux更新数据: ${userInfo.name}");
}),
new Padding(
padding: const EdgeInsets.only(top: 15.0),
child:
StoreConnector(
converter: (store) {
var newUserInfo=User("把用户名字更新为无用");
return () => store.dispatch(new UpdateUserAction(newUserInfo));
},
builder: (context, callback) {
return FloatingActionButton(
onPressed: callback,
child: Icon(Icons.add),
);
},
)
),
],
);
}),
),
);
},
);
}
Widget dividerWidget = new Container(
//margin: const EdgeInsets.only( left: 10.0,right: 10.0),
child: new Padding(
padding: const EdgeInsets.only(left: 0.0, right: 0.0),
child:
new Divider(height: 1.0, indent: 0.0, color: Color(0xFFe5e5e5))
)
);
@override
void dispose() {
super.dispose();
}
}
也可以把上面的StoreConnector更换成使用 StoreBuilder 获取 store 中的state数据变化而刷新UI,效果是一样的而且使用起来更加方便些
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';
import 'package:ydcflutter_app/redux/user_redux.dart';
import 'package:ydcflutter_app/test/bean/User.dart';
import 'package:ydcflutter_app/test/bean/YDCState.dart';
class TestReduxPage extends StatefulWidget {
@override
State createState() => new _TestReduxPageState();
}
class _TestReduxPageState extends State {
BuildContext mContext;
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
//使用 StoreBuilder 获取 store 中的state数据
return new StoreBuilder(
builder: (context, store) {
return new Scaffold(
body: Center(
child: Builder(builder: (context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Builder(builder: (context) {
return Text("使用Redux更新数据: ${store.state.user.name??"---"}");
}),
new Padding(
padding: const EdgeInsets.only(top: 15.0),
child:
new FloatingActionButton(
onPressed: (){
var newUserInfo=User("把用户名字更新为无用");
store.dispatch(new UpdateUserAction(newUserInfo));
},
child: Icon(Icons.add),
)
)
]
);
}))
);
});
}
Widget dividerWidget = new Container(
//margin: const EdgeInsets.only( left: 10.0,right: 10.0),
child: new Padding(
padding: const EdgeInsets.only(left: 0.0, right: 0.0),
child:
new Divider(height: 1.0, indent: 0.0, color: Color(0xFFe5e5e5))
)
);
@override
void dispose() {
super.dispose();
}
}
Flutter商城项目实战:https://github.com/dechengyang/ydc_flutter_app
如果对你有帮助,随意赏我奶粉钱吧,多谢!
微信:
支付宝: