内容简介:一直都在自己的 React Native 应用中使用 Redux,其实更大情况下也是使用它来管理应用的会话状态以及当前登录的用户信息等等简单的数据,很好用,自从 Google 发布 Flutter 之后,就一直想着拿它来做点啥,准备拿一个新项目开刀,先研究下怎么把以前在 React Native 中需要用到的一些技术在 Flutter 找到对应的实现方法,本文记录下 Flutter + Redux + Redux Persist 的实现。Flutter 项目必须是一个合法的 Dart 包,而 Dart 包
一直都在自己的 React Native 应用中使用 Redux,其实更大情况下也是使用它来管理应用的会话状态以及当前登录的用户信息等等简单的数据,很好用,自从 Google 发布 Flutter 之后,就一直想着拿它来做点啥,准备拿一个新项目开刀,先研究下怎么把以前在 React Native 中需要用到的一些技术在 Flutter 找到对应的实现方法,本文记录下 Flutter + Redux + Redux Persist 的实现。
第一步:创建一个新的应用: redux_demo_app
flutter create redux_demo_app cd redux_demo_app code . 复制代码
Flutter 项目必须是一个合法的 Dart 包,而 Dart 包要求使用纯小写字母(可包含下划线),这个跟 React Native 是不一样的。
第二步:添加依懒
我们依懒下面这些包:
- Redux : JavaScript Redux 的复刻版
- Flutter Redux:类似于 React Redux 一样,让我们在 Flutter 项目中更好的使用 Redux
- Redux Persist:Redux 持久化
- Redux Persist Flutter :Flutter Redux Persist 引擎
打开 pubspec.yaml
,在 dependencies
中添加下面这些依懒:
... dependencies: ... redux: ^3.0.0 flutter_redux: ^0.5.2 redux_persist: ^0.8.0 redux_persist_flutter: ^0.8.0 dev_dependencies: ... ... 复制代码
第三步:了解需求
本次我想做的一个App有下面四个页面:
- 首页
- 个人中心页
- 个人资料详情页
- 登录页
交互是下面这样的:
- 应用打开之后,打开的是一个有两个底部 Tab 的应用,默认展示的是首页
-
当用户点击(我的)这个Tab时:
- 若当前用户已登录,则Tab切换为个人中心页
- 若当前用户未登录,则以 Modal 的方式弹出登录页
添加 lib/state.dart
文件
内容如下:
enum Actions{
login,
logout
}
/// App 状态
///
/// 状态中所有数据都应该是只读的,所以,全部以 get 的方式提供对外访问,不提供 set 方法
class AppState {
/// J.W.T
String _authorizationToken;
// 获取当前的认证 Token
get authorizationToken => _authorizationToken;
// 获取当前是否处于已认证状态
get authed => _authorizationToken.length > 0;
AppState(this._authorizationToken);
}
/// Reducer
AppState reducer(AppState state, action) {
switch(action) {
case Actions.login:
return AppState('J.W.T');
case Actions.logout:
return AppState('');
default:
return state;
}
}
复制代码
在上面的代码中,我们先声明了 Actions
枚举,以及一个 AppState
类,该类就是我们的应用状态类,使用 _authorizationToken
保证认证的值不可被实例外直接被访问到,这样用户就无法去直接修改它的值,再提供了两个 get
方法,提供给外部访问它的值。
接着我们定义了一个 reducer
函数,用于更新状态。
创建 app.dart
import 'package:flutter/material.dart';
import 'package:redux/redux.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'state.dart';
import 'root.dart';
/// 示例App
class DemoApp extends StatelessWidget {
// app store
final Store<AppState> store;
DemoApp(this.store);
@override
Widget build(BuildContext context) {
return StoreProvider<AppState>(
store: store,
child: new MaterialApp(
title: 'Flutter Redux Demo App',
// home 为 root 页
home: Root()
),
);
}
}
复制代码
在上面我们已经完成的 App
类的编码,现在需要完成 Root
页,也就是我们的App入口页。
创建 Root
页
import 'package:flutter/material.dart';
import 'package:redux/redux.dart';
import 'package:flutter_redux/flutter_redux.dart';
/// 状态
import 'state.dart';
/// 登录页面
import 'auth.dart';
/// 我的页面
import 'me.dart';
/// 首页
import 'home.dart';
/// 应用入口页
class Root extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _RootState();
}
}
/// 入口页状态
class _RootState extends State<Root> {
/// 当前被激活的 Tab Index
int _currentTabIndex;
/// 所有 Tab 列表页
List<Widget> _tabPages;
@override
void initState() {
super.initState();
// 初始化 tab 为第 0 个
_currentTabIndex = 0;
// 初始化页面列表
_tabPages = <Widget>[
// 首页
Home(),
// 我的
Me()
];
}
@override
Widget build(BuildContext context) {
// 使用 StoreConnector 创建 Widget
// 类似于 React Redux 的 connect,链接 store state 与 Widget
return StoreConnector<AppState, Store<AppState>>(
// store 转换器,类似于 react redux 中的 mapStateToProps 方法
// 接受参数为 `store`,再返回的数据可以被在 `builder` 函数中使用,
// 在此处,我们直接返回整个 store,
converter: (store) => store,
// 构建器,第二个参数 store 就是上一个 converter 函数返回的 store
builder: (context, store) {
// 取得当前是否已登录状态
final authed = store.state.authed;
return new Scaffold(
// 如果已登录,则直接可以访问所有页面,否则展示 Home
body: authed ? _tabPages[_currentTabIndex] : Home(),
// 底部Tab航
bottomNavigationBar: BottomNavigationBar(
onTap: (int index) {
// 如果点击的是第 1 个Tab,且当前用户未登录,则直接打开登录 Modal 页
if (!authed && index == 1) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Auth(),
fullscreenDialog: true
)
);
// 否则直接进入相应页面
} else {
setState(() {
_currentTabIndex = index;
});
}
},
// 与 body 取值方式类似
currentIndex: authed ? _currentTabIndex : 0,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('首页')
),
BottomNavigationBarItem(
icon: Icon(Icons.people),
title: Text('我的')
)
],
),
);
},
);
}
}
复制代码
创建 Home
与 Root
页面类似,我们可以在任何页面方便的使用 AppState
import 'package:flutter/material.dart';
import 'package:redux/redux.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'state.dart';
import 'auth.dart';
class Home extends StatefulWidget {
@override
State<StatefulWidget> createState() => _HomeState();
}
class _HomeState extends State<Home> {
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, Store<AppState>>(
converter: (store) => store,
builder: (context, store) {
return Scaffold(
appBar: AppBar(
title: Text('首页'),
),
body: Center(
child: store.state.authed
? Text('您已登录')
: FlatButton(
child: Text('去登录'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Auth(),
fullscreenDialog: true
)
);
},
)
),
);
},
);
}
}
复制代码
完成 Auth
在前面的所有页面中,都只是对 store
中状态树的读取,现在的 Auth
就需要完成对状态树的更新了,看下面代码:
import 'package:flutter/material.dart';
import 'package:redux/redux.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'state.dart';
class Auth extends StatefulWidget {
@override
State<StatefulWidget> createState() => _AuthState();
}
class _AuthState extends State<Auth> {
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, Store<AppState>>(
converter: (store) => store,
builder: (context, store) {
return Scaffold(
appBar: AppBar(
title: Text('登录'),
),
body: Center(
child: FlatButton(
child: Text('登录'),
onPressed: () {
// 通过 store.dispatch 函数,可以发出 action(跟 Redux 是一样的),而 Action 是在
// AppState 中定义的枚举 Actions.login
store.dispatch(Actions.login);
// 之后,关闭当前的 Modal,就可以看到应用所有数据都更新了
Navigator.pop(context);
},
)
),
);
},
);
}
}
复制代码
创建 Me
有了登录之后,我们可以在做一个我的页面,在这个页面里面我们可以完成退出功能。
import 'package:flutter/material.dart';
import 'package:redux/redux.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'state.dart';
class Me extends StatefulWidget {
@override
State<StatefulWidget> createState() => _MeState();
}
class _MeState extends State<Me> {
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, Store<AppState>>(
converter: (store) => store,
builder: (context, store) {
return Scaffold(
appBar: AppBar(
title: Text('退出'),
),
body: Center(
child: FlatButton(
child: Text('退出'),
onPressed: () {
store.dispatch(Actions.logout);
// 此处我们不需要去更新Tab Index,在 Root 页面中,对 store 里面的 authed 值已经做了监听,如果
// Actions.logout 被触发后, authed 的值会变成 false,那么App将自动切换首页
},
)
),
);
},
);
}
}
复制代码
添加状态持久化
在上面,我们已经完成了一个基于 Redux 的同步状态的App,但是当你的App关闭重新打开之外,状态树就会被重置为初始值,这并不理想,我们经常需要一个用户完成登录之后,就可以在一断时间内一直保持这个登录状态,而且有一些数据我们并不希望每次打开App的时候都重新初始化一次,这个时候,可以考虑对状态进行持久化了。
更新 state.dart
class AppState {
...
// 持久化时,从 JSON 中初始化新的状态
static AppState fromJson(dynamic json) => json != null ? AppState(json['authorizationToken'] as String) : AppState('');
// 更新状态之后,转成 JSON,然后持久化至持久化引擎中
dynamic toJson() => {'authorizationToken': _authorizationToken};
}
复制代码
这里我们添加了两个方法,一个是静态的 fromJson
方法,它将在初始化状态树时被调用,用于从 JSON 中初始化一个新的状态树出来, toJson
将被用于持久化,将自身转成 JSON。
更新 main.dart
import 'package:flutter/material.dart';
import 'package:redux/redux.dart';
import 'package:redux_persist/redux_persist.dart';
import 'package:redux_persist_flutter/redux_persist_flutter.dart';
import 'app.dart';
import 'state.dart';
void main() async {
// 创建一个持久化器
final persistor = Persistor<AppState>(
storage: FlutterStorage(),
serializer: JsonSerializer<AppState>(AppState.fromJson),
debug: true
);
// 从 persistor 中加载上一次存储的状态
final initialState = await persistor.load();
final store = Store<AppState>(
reducer,
initialState: initialState ?? AppState(''),
middleware: [persistor.createMiddleware()]
);
runApp(new DemoApp(store));
}
复制代码
重新 flutter run
当前应用,即完成了持久化,可以登录,然后退出应用,再重新打开应用,可以看到上一次的登录状态是存在的。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Alone Together
Sherry Turkle / Basic Books / 2011-1-11 / USD 28.95
Consider Facebookit’s human contact, only easier to engage with and easier to avoid. Developing technology promises closeness. Sometimes it delivers, but much of our modern life leaves us less connect......一起来看看 《Alone Together》 这本书的介绍吧!