Flutter状态管理插件Okito的使用
Flutter状态管理插件Okito的使用
特性
状态管理
创建控制器
class CounterController extends OkitoController {
int count = 0;
void increment() => setState(() => count++);
void decrement() {
count--;
update();
}
}
CounterController counterController = CounterController();
你也可以使用 setStateAsync
函数来异步更新数据。
使用控制器
OkitoBuilder(
controller: counterController,
builder: () => Text('${counterController.count}'),
);
更新控制器
main(){
// 你可以从任何地方更改状态,而无需上下文!
counterController.increment();
}
// 在Flutter中
ElevatedButton(
onPressed: counterController.increment,
child: const Text('Increment'),
)
// 或者
ElevatedButton(
onPressed: () => counterController.setState(() => counterController.count--),
child: const Text('Decrement'),
)
Rockitos
Rockitos 是我们使用依赖注入进行状态管理的方式!
// Rockito - 我最喜欢使用Okito状态的方式。
Rockito<CounterController>(
(controller) => Text('${controller.count}')
);
// 非常简单吧?
// 要使用 Rockito,你应该首先注入 CounterController。
Okito.inject(CounterController);
// RockitoBuilder - Rockito但具有更多功能和构建器!
RockitoBuilder<CounterController>(
inject: CounterController(), // 可选,如果你还没有注入它。
builder: (controller) => Text('${controller.count}'),
// 你可以在这里使用所有 OkitoBuilder 的功能,比如 otherControllers 等等。
);
监视控制器
OkitoWatcher(
watch: counterController,
onChange: (CounterController controller) {
// 你也可以在那里更新状态。
// onChange 给你的就是控制器的实例。
print(controller.count);
},
);
counterController.increment();
// OkitoWatcher 还会返回一个停止监视的函数,这可以减少内存使用,当你不再需要时可以使用它。
final stopWatching = OkitoWatcher(/* 代码在此 */);
// 做你想做的事情,然后:
stopWatching();
// 你也可以用 Rockitos 来监视。
RockitoWatcher<CounterController>(
(controller) => print(controller.count)
);
// 你必须先注入控制器。
状态方法
状态方法类似于 Flutter 中的 State
类的方法。
class CounterController extends OkitoController{
int count = 0;
// 当你的 [OkitoBuilder] 挂载到小部件树时将被调用。
@override
void initState() {
count++;
}
// 当你的 [OkitoBuilder] 从小部件树中移除时将被调用。
@override
void dispose() {
count = 0;
}
// 当你使用 Okito 的注入方法时将被调用。
@override
void onInject() {
count++;
}
}
我个人在使用控制器作为 StatefulWidget 替换器时使用状态方法。
class EditProductController extends OkitoController {
// 其他节点在此
final priceFocusNode = FocusNode();
void submitForm(){
// 我在这里使用我的 inputControllers 获取它们的值。
// 然后我使用我的 Okito 路由而不使用上下文!
Okito.pushNamed('/productUpdatedSuccessfully/31')
}
@override
void dispose() {
// 其他节点在这里 [dispose]。
priceFocusNode.dispose();
}
}
流
你可能在应用中使用了流,并且可能希望监视它们,根据变化更新状态等等。
class YourController extends OkitoController with OkitoStreamMixin{
// 你的代码,完全一样。
}
// 对于常规流。
class CounterController extends OkitoController with OkitoStreamMixin {
int count = 0;
@override
void onInject(){
initStream<int>(stream: yourIntStream, onData(data) {
count = data; // 你不需要做任何事情或更新。
});
}
}
// 对于 Firestore 查询流
// 使用时,你需要获取查询的快照作为流。
class PeopleController extends OkitoController with OkitoStreamMixin {
List<Person> people = [];
@override // 或者,你可以使用构造函数。
void onInject(){
initFirestoreQueryStream(querySnapshot: querySnapshot, onData(data) {
// 这些数据是你集合中的文档(映射)列表。
people = data;
});
}
}
// 对于 Firestore 查询流
// 使用时,你需要获取查询的快照作为流。
class PersonController extends OkitoController with OkitoStreamMixin{
Person person = Person();
@override // 或者,你可以使用构造函数。
void onInject(){
initFirestoreDocumentStream(
documentSnapshot: documentSnapshot,
onData(data) {
// 这些数据是你的文档作为映射。
person = Person.fromMap(data);
});
}
}
工具
导航和使用不带上下文的小部件
首先,我们应该用 Okito 包裹我们的应用或手动提供 Okito。
// 基本上,你应该在你的应用开始处添加 *Okito* 或手动提供 key/observers。
OkitoMaterialApp(/* 所有东西都与 [MaterialApp] 相同 */);
// 或者
OkitoCupertinoApp(/* 所有东西都与 [CupertinoApp] 相同 */);
// 或者
Material/CupertinoApp(
navigatorKey: Okito.navigatorKey,
navigatorObservers: [OkitoObserver()]);
然后你就可以使用所有 Okito 的好处!
Okito.width;
Okito.height;
Okito.aspectRatio;
Okito.devicePixelRatio;
Okito.isLandscape;
Okito.isPortrait;
Okito.theme;
Okito.showSnackBar();
Okito.showToast(); // 不带小部件的 Snackbar,适合简单的使用。
Okito.showModal();
Okito.showDialog();
Okito.push();
Okito.pushReplacement();
Okito.pushNamed();
Okito.pushReplacementNamed();
Okito.pop();
Okito.arguments;
Okito.routeName;
路由管理
假设你想创建动态 URL,例如:
/posts/:id
/posts/23
这个 id 是一个动态变量,对吗?
使用 Okito,你可以轻松地做到这一点!
// 你不需要添加像 OkitoPage 或其他东西。
// Okito 让你不用改变代码就能完成任务。
OkitoMaterialApp(
routes: {
'/': (ctx) => FirstPage(),
'/second/:id': (ctx) => SecondPage(),
}
);
现在,每当你尝试这样做时:
ElevatedButton(
onPressed: () => Okito.pushNamed(
// 你可以添加任何类型的参数
'/second/33?name=Rago&postId=123&isMaterial=true',
arguments: 'This is an extra argument'),
child: const Text('Go to second page'),
)
它将把页面推送到第二个页面,参数 [id] : [33]
此外,你会看到你的参数如下:
print(Okito.arguments);
// 结果
{'id' : '33', 'name' : 'Rago', 'postId' : 123, 'isMaterial' : true, 'arguments': 'This is an extra argument'};
// 是的,你甚至可以手动获取额外的参数。
检查 example/flutter_dynamic_routing/lib/main.dart
以查看实时示例。
主题管理
// 首先,底部的方法给你应用程序控制器,你可以手动更新任何东西。
Okito.app; /* 或 */ Okito.use<AppController>();
// 然后你将拥有它的所有用法。
Okito.app.setThemeData();
Okito.app.setThemeMode();
Okito.app.setCupertinoThemeData();
Okito.app.locale;
Okito.app.setLocale();
本地存储
OkitoStorage
是一种将变量保存到本地存储的方法。
// 它的工作方式类似于 SharedPereferences,但它同步,就像 GetStorage。
// 要使用,你应该初始化存储,这在 Web 上不是必需的,但在其他平台上是必需的。
void main() async{
// 只有初始化是异步的,你也可以在没有 await 的情况下调用它,但这不推荐。
await OkitoStorage.init();
// 使用
final box = OkitoStorage; // 为了更方便的引用。
box.write('count', 0);
final int count = box.read<int>('count');
// 就这么简单!
print('Count is $count');
// 你的其余代码将在这里。
}
其他用法
box.watchKey('count', () =>
print('这个函数将在计数改变时被调用。')
);
box.watchAll(() =>
print('这个函数将在存储改变时被调用。')
);
box.removeKey('count'); // 移除键
box.readAllKeys(); // 返回存储中的所有键
box.readAllValues(); // 返回存储中的所有值
box.readAll(); // 返回整个存储
box.clearStorage(); // 从存储中删除所有内容,但存储仍然存在。
box.deleteStorage(); // 从文件系统中完全删除存储,在此操作之后,OkitoStorage 将无法写入或读取。
使用 OkitoBuilder 观察 OkitoStorage
// 查看 example/flutter_okito_storage/lib/main.dart 以获取更多示例!
// 每当 'count' 键发生变化时都会运行。
OkitoBuilder(
controller: yourController,
watchStorageKeys: ['count'],
builder: () => Text('${box.read('count')}'),
);
OkitoStorage 的优点
- 极速
- 你可以从任何地方观察更改,甚至在你的构建器中
- 它是同步的,所以你不需要使用 ‘await’ 关键字
- 你可以存储字符串、整数、映射甚至列表
- 在支持 Flutter 的任何设备上工作!
注意
OkitoStorage 是可靠的,但在将其用作数据库时要小心,因为它不是为复杂工作设计的数据库。对于复杂的工作,你可以试试 Hive!
本地化
对于全球应用,找到一个新的本地化库或创建自己的可能会很困难,然后你可能会遇到其他问题,比如更改语言后更新整个应用等等。为什么要做这些呢?
Okito 提供本地化解决方案
// 创建你的翻译,非常简单!
const translations = {
'en': {
'hello': 'Hello from Okito!',
},
'tr': {
'hello': "Okito'dan selamlar!",
},
};
// 你可以有无限数量的区域和翻译
// 你可以使其动态,分离文件等等。只是一个 Dart 映射!
// 创建后,将其传递给应用。
OkitoMaterialApp /* 或 OkitoCupertinoApp */(
translations: translations,
/* 你的代码这里没有任何变化 */
);
// 使用它?很简单!让我们在一个文本小部件中使用它。
Text('hello'.loc); // 它将显示 'Hello from Okito!'
// 改变语言再看看。
Okito.app.setLocale(Locale('tr','TR'));
// 现在它说: 'Okito'dan selamlar!' 如在翻译中声明的一样。
// 你也可以这样设置:
Okito.localize('hello'); // 返回翻译为字符串。
更好的例子请查看 example/flutter_localization/lib/main.dart
扩展
// 上下文扩展
context.width;
context.height;
context.aspectRatio;
context.devicePixelRatio;
context.isLandscape;
context.isPortrait;
context.theme;
context.arguments;
context.routeName;
依赖注入
依赖注入是你的方法,将变量注入到 Okito
并可以在应用的任何地方使用它。使用 Okito
,它是如此简单!
// 示例变量
class Counter {
int count = 0;
}
// 注入它
Okito.inject(Counter());
// 在任何地方使用它!
Okito.use<Counter>();
// 用类型支持分配它!
final counter = Okito.use<Counter>();
// 无论你想要如何更新
counter.count++;
// 或
Okito.use<Counter>().count++;
那么,假设你的工作已经完成了,为什么要让它占用内存?
// Counter 将永远消失!
Okito.eject<Counter>();
更多细节,请查看测试或示例
使用键进行注入
当你要使用字符串键而不是类型存储多个相同类型的注入时,这很有用。
// 示例变量
class Counter {
int count = 0;
}
// 注入它
Okito.injectWithKey('firstCounter', Counter());
Okito.injectWithKey('secondCounter', Counter());
// 使用类型支持在任何地方使用它!
final firstCounter = Okito.useWithKey<Counter>('firstCounter');
final secondCounter = Okito.useWithKey<Counter>('secondCounter');
// 无论你想要如何更新
firstCounter.count++;
secondCounter.count++;
那么,假设你的工作已经完成了,为什么要让它占用内存?
// 第二个计数器将永远消失!
Okito.ejectWithKey('secondCounter');
技巧
清洁小部件
// 在你的小部件文件夹或其他文件夹中声明构建器。
OkitoBuilder CounterBuilder({
required Widget Function() builder,
}) =>
OkitoBuilder(
controller: counterController,
builder: () => builder(),
);
// 使用
CounterBuilder(builder: () => Text('${counterController.count}'));
我最喜欢的方式
OkitoBuilder CounterBuilder({
required Widget Function(CounterController state) builder,
}) =>
OkitoBuilder(
controller: counterController,
builder: () => builder(counterController),
);
// 使用
CounterBuilder(builder: (state) => Text('${state.count}'));
更新状态
class CounterController extends OkitoController {
int _count = 0;
int get count => _count;
set count(int count) {
_count = count;
// 现在,每当你改变 count 像 'count++',它将更新状态。
update();
}
}
应用控制器
它是应用的控制器,你可以包装你想要根据大更新更改的小部件,比如主题更改,如果数据不是来自控制器。
Rockito<AppController>(
(app) => // 你的小部件
)
更多关于Flutter状态管理插件Okito的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter状态管理插件Okito的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
Okito
是一个轻量级且易于使用的状态管理和依赖注入库,专为 Flutter 应用设计。它提供了简单而强大的工具来管理应用的状态和依赖关系,同时保持了代码的简洁性和可维护性。以下是如何使用 Okito 进行状态管理的基本指南。
1. 添加依赖
首先,你需要在 pubspec.yaml
文件中添加 Okito 的依赖:
dependencies:
flutter:
sdk: flutter
okito: ^3.0.0
然后运行 flutter pub get
来安装依赖。
2. 创建一个状态管理类
你可以通过继承 OkitoStore
来创建一个状态管理类。这个类将包含你的应用状态和操作状态的方法。
import 'package:okito/okito.dart';
class CounterStore extends OkitoStore {
int count = 0;
void increment() {
count++;
notify();
}
void decrement() {
count--;
notify();
}
}
3. 在应用中使用 Okito
你可以在应用的任何地方使用 Okito
来访问状态和管理依赖。
import 'package:flutter/material.dart';
import 'package:okito/okito.dart';
import 'counter_store.dart';
void main() {
// 初始化 Okito
Okito.runApp(MyApp());
// 注册 CounterStore
Okito.inject(CounterStore());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 获取 CounterStore 实例
final counterStore = Okito.use<CounterStore>();
return Scaffold(
appBar: AppBar(title: Text('Okito Counter Example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Count: ${counterStore.count}'),
SizedBox(height: 20),
ElevatedButton(
onPressed: () => counterStore.increment(),
child: Text('Increment'),
),
ElevatedButton(
onPressed: () => counterStore.decrement(),
child: Text('Decrement'),
),
],
),
),
);
}
}
4. 响应状态变化
通过在 OkitoStore
中调用 notify()
方法,你可以通知所有订阅者状态已经发生了变化。Okito.use<T>()
会自动订阅状态变化,并在状态更新时重新构建 UI。
5. 依赖注入
Okito
还提供了依赖注入功能。你可以在应用启动时注册依赖项,然后在任何需要使用它们的地方获取这些依赖项。
void main() {
Okito.runApp(MyApp());
// 注册依赖项
Okito.inject(CounterStore());
Okito.inject(SomeOtherService());
}
class SomeWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final someService = Okito.use<SomeOtherService>();
// 使用 someService
return Container();
}
}
6. 路由管理
Okito
还提供了简单的路由管理功能。你可以使用 Okito.push
, Okito.pop
, Okito.replace
等方法来管理导航。
Okito.push(MaterialPageRoute(builder: (context) => AnotherPage()));