Flutter数据持久化插件rxstore的使用
Flutter数据持久化插件rxstore的使用
RxStore 是一个基于流的 Redux 实现,支持副作用处理。
概念
Store 包含了应用的所有状态,这些状态不能直接被修改。要改变状态,必须分发一个动作(Action),它只是一个数据对象。你可以将动作视为解释某些更改原因的面包屑。Reducer 是一个函数,它接受一个动作和当前状态,并返回下一个状态。然后,Store 将新的状态发射给其订阅者。
Reducer 是纯函数且是同步的。异步任务和副作用应在 Epic 中处理。Epic 是一个函数,它接受一个动作和当前状态,并返回一个动作的流。Epic 不能改变状态,但可以返回其他动作,这些动作由可以改变状态的 Reducer 处理。这使得调试变得更加容易。
状态
首先,定义应用的状态。建议使用不可变状态,可以使用像 built_value
或 freezed
这样的库来实现,但为了简单起见,我们这里使用普通的 Dart 类:
class AppState {
AppState({required this.toDoList, required this.showCompleted});
final List<ToDo> toDoList;
final bool showCompleted;
}
class ToDo {
ToDo({required this.text, required this.completed});
final String text;
final bool completed;
}
动作
动作是一个描述发生了什么的对象。它只是一个数据,没有逻辑。以下是一个简单的动作,用于向列表中添加一个新的待办事项:
class AddToDo implements Action {
AddToDo({required this.text});
final String text;
}
减少器
减少器是唯一更新状态的方法。它接受当前状态和动作作为参数,并返回下一个状态。由于减少器是纯函数,因此它们易于测试和调试。
AppState reducer(AppState state, Action action) {
if (action is AddToDo) {
return AppState(
toDoList: [...state.toDoList, ToDo(text: action.text, completed: false)], showCompleted: state.showCompleted);
}
return state;
}
Epic
Epic 用于处理异步任务,如调用 REST 端点或读取文件。与减少器一样,它接受当前状态和动作作为参数,但它返回的是动作的流。这些动作会被再次传递给所有减少器和 Epic,因此确保只处理你感兴趣的事件,以避免编写循环。
// 创建一个 Epic,仅响应 FetchToDoList 动作并调用 _fetchToDoList
Stream<Action> epic(Stream<Action> actions, ValueStream<AppState> state) =>
actions.whereType<FetchToDoList>() // 过滤 FetchToDoList 动作
.switchMap((FetchToDoList action) => _fetchToDoList(action));
Stream<Action> _fetchToDoList(FetchToDoList action) async* {
yield const FetchingToDoList(); // 减少器可以设置加载标志为 true
// 异步调用服务器
final response = await client.fetchToDoList();
if (response.statusCode == HttpStatus.ok) {
// 所有正常,返回带有列表的动作
yield FetchedToDoList(list: response.items, error: null);
} else {
// 发生错误,返回详细说明错误的动作
yield FetchedToDoList(list: null, error: 'Something went wrong');
}
}
Store
Store 将状态、减少器和可选的 Epic 绑定在一起。
创建 Store 时,至少需要传递一个减少器和初始状态:
final store = Store<AppState>(
reducer,
initialState: AppState(toDoList: [], showCompleted: true),
);
// 如果有 Epic,可以在构造函数中传递
final store = Store<AppState>(
reducer,
initialState: AppState(toDoList: [], showCompleted: true),
epic: epic,
);
监听 Store
Store 暴露了一个流,始终发出最新的状态。你可以使用它来对状态变化做出反应。
订阅时,即使状态在那之前没有改变,你也会立即得到当前状态。
store.state.listen(print);
如何定义多个减少器/Epic?
该库提供两个帮助函数来完成此操作,combineReducers
和 combineEpics
:
final rootReducer = combineReducers([reducerOne, reducerTwo, reducerThree]);
final rootEpic = combineEpics([epicOne, epicTwo, epicThree]);
这两个函数分别返回一个普通的减少器和 Epic,你可以再次使用它们进行组合调用或将它们传递给 Store。
帮助!我写了一个循环…
每个由 Epic 返回的动作也会被相同的 Epic 接收。只要你不返回 Epic 正在处理的动作类型,就不会引入任何循环。
// 无限循环:处理并返回所有动作
Stream<Action> epic(Stream<Action> actions, ValueStream<AppState> state) => actions;
// 无限循环:过滤某种类型但仍然返回相同类型
Stream<Action> epic(Stream<Action> actions, ValueStream<AppState> state) =>
actions.whereType<FetchToDoList>();
// 无循环:处理 FetchToDoList 类型的动作,但返回 FetchingToDoList
Stream<Action> epic(Stream<Action> actions, ValueStream<AppState> state) =>
actions.whereType<FetchToDoList>()
.switchMap((FetchToDoList action) => const FetchingToDoList());
更多关于Flutter数据持久化插件rxstore的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter数据持久化插件rxstore的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter中使用rxstore
插件进行数据持久化的代码案例。rxstore
是一个轻量级的、响应式的Flutter本地存储库,适用于存储和管理应用状态。
首先,确保你已经在pubspec.yaml
文件中添加了rxstore
依赖:
dependencies:
flutter:
sdk: flutter
rxstore: ^最新版本号 # 请替换为实际的最新版本号
然后,运行flutter pub get
来获取依赖。
接下来,我们将展示如何使用rxstore
进行简单的数据持久化操作。
1. 初始化RxStore
首先,我们需要创建一个RxStore
实例。在这个例子中,我们将存储一个简单的用户对象。
import 'package:flutter/material.dart';
import 'package:rxstore/rxstore.dart';
class User {
String name;
int age;
User({required this.name, required this.age});
User.fromJson(Map<String, dynamic> json)
: name = json['name'],
age = json['age'];
Map<String, dynamic> toJson() => {'name': name, 'age': age};
}
class UserStore extends RxStore<User> {
UserStore() : super(initialState: User(name: '', age: 0));
void setName(String name) {
update((state) => User(name: name, age: state.age));
}
void setAge(int age) {
update((state) => User(name: state.name, age: age));
}
}
2. 使用Provider管理状态
我们可以使用Provider
包来管理我们的UserStore
实例,这样可以在整个应用中轻松访问和更新用户数据。
在main.dart
中设置Provider:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'user_store.dart';
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => UserStore()),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
3. 在UI中使用RxStore
现在,我们可以在UI组件中使用Consumer
或Selector
来访问和更新用户数据。
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'user_store.dart';
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final userStore = Provider.of<UserStore>(context);
return Scaffold(
appBar: AppBar(
title: Text('RxStore Demo'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
decoration: InputDecoration(labelText: 'Name'),
onChanged: (value) {
userStore.setName(value);
},
),
SizedBox(height: 16),
TextField(
decoration: InputDecoration(labelText: 'Age'),
keyboardType: TextInputType.number,
onChanged: (value) {
if (value.isNotEmpty) {
userStore.setAge(int.parse(value));
}
},
),
SizedBox(height: 16),
Text('User Data: ${userStore.state.toJson()}'),
],
),
),
);
}
}
4. 数据持久化
rxstore
本身并不直接提供持久化功能,但你可以结合其他持久化方案(如shared_preferences
、hive
或sqflite
)来实现。在这个例子中,我们将展示如何在应用启动时从持久化存储加载数据,以及在数据更新时保存到持久化存储。
这里我们使用shared_preferences
作为示例:
首先,添加shared_preferences
依赖:
dependencies:
shared_preferences: ^最新版本号 # 请替换为实际的最新版本号
然后,修改UserStore
以包含持久化逻辑:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:rxstore/rxstore.dart';
import 'package:shared_preferences/shared_preferences.dart';
class UserStore extends RxStore<User> {
UserStore() {
_loadUser();
}
late SharedPreferences _preferences;
Future<void> _loadUser() async {
_preferences = await SharedPreferences.getInstance();
final userJson = _preferences.getString('user');
User? user;
if (userJson != null) {
user = User.fromJson(jsonDecode(userJson));
}
super.initialState = user ?? User(name: '', age: 0);
}
@override
void notifyListeners() {
super.notifyListeners();
_saveUser();
}
void _saveUser() {
_preferences.setString('user', jsonEncode(state.toJson()));
}
void setName(String name) {
update((state) => User(name: name, age: state.age));
}
void setAge(int age) {
update((state) => User(name: state.name, age: age));
}
}
在这个修改后的UserStore
中,我们在构造函数中加载用户数据,并在每次状态更新时保存用户数据。
现在,你的Flutter应用已经能够使用rxstore
进行响应式状态管理,并结合shared_preferences
实现数据持久化。