Flutter状态管理插件riverpod_hook_mutation的使用
Flutter状态管理插件riverpod_hook_mutation的使用
Riverpod and hook mutation package
这是一个提供简单方式在Riverpod中管理mutations的包。
Inspiration
解决Riverpod中的mutation问题:https://github.com/rrousselGit/riverpod/issues/1660
Features
- ✅ 使用hooks进行mutation
- ✅ 使用provider进行mutation
- ✅ 使用Flutter的
ValueNotifier
和AsyncSnapshot
来通知状态变化
Getting Started
为了使用这个包,你需要在你的pubspec.yaml
文件中添加riverpod_hook_mutation
作为依赖项。
dependencies:
riverpod_hook_mutation: ^0.0.1
然后,运行flutter pub get
来获取包。
Usage
以下是一个完整的示例代码,展示了如何使用riverpod_hook_mutation
来管理状态。
示例代码
主入口文件 main.dart
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:riverpod_hook_mutation/riverpod_hook_mutation.dart';
part 'main.g.dart';
Future<void> main() async {
runApp(
const ProviderScope(
child: MaterialApp(
home: TodosScreen(),
),
),
);
}
class TodoRepository {
static final TodoRepository _instance = TodoRepository._internal();
factory TodoRepository() => _instance;
TodoRepository._internal();
final _todos = [
TodoModel(
title: 'Buy milk',
completed: false,
),
TodoModel(
title: 'Buy eggs',
completed: true,
),
TodoModel(
title: 'Buy bread',
completed: false,
),
];
Future<List<TodoModel>> fetchTodos() async {
await Future.delayed(const Duration(seconds: 3));
return _todos;
}
Future<TodoModel> createTodo() async {
return Future.delayed(const Duration(seconds: 3), () {
final todo = TodoModel(
title: 'Buy cheese ${Random().nextInt(1000000)}',
completed: false,
);
_todos.add(todo);
return todo;
});
}
}
class TodoModel {
final String title;
final bool completed;
TodoModel({
required this.title,
required this.completed,
});
Map<String, dynamic> toJson() {
return {
'title': title,
'completed': completed,
};
}
}
@riverpod
class Todos extends _$Todos {
TodoRepository get _repository => TodoRepository();
@override
Future<List<TodoModel>> build() {
return _repository.fetchTodos();
}
Future<TodoModel> addTodo() async {
final result = await _repository.createTodo();
ref.invalidateSelf();
if (kDebugMode) print(result.toJson());
return result;
}
}
class TodosScreen extends HookConsumerWidget {
const TodosScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final provider = todosProvider;
final todos = ref.watch(provider);
return Scaffold(
appBar: AppBar(
actions: [
FloatingActionButton.small(
heroTag: null,
child: const Icon(Icons.add),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) {
return const ItemAddScreen();
},
),
);
},
)
],
),
body: todos.when(
data: (data) {
return RefreshIndicator(
onRefresh: () => ref.read(provider.future),
child: ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
final todo = data[index];
return ListTile(
title: Text(todo.title),
);
},
),
);
},
error: (error, stackTrace) {
return Center(
child: Text('Error: $error'),
);
},
loading: () {
return const Center(
child: CircularProgressIndicator(),
);
},
),
);
}
}
class ItemAddScreen extends HookConsumerWidget {
const ItemAddScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final addTodo = useMutation<TodoModel>();
return Scaffold(
appBar: AppBar(),
body: Column(
children: [
addTodo.when(
idle: () {
return const Icon(Icons.add);
},
data: (data) {
return const Icon(Icons.add);
},
error: (error, stackTrace) {
return const Icon(Icons.error);
},
loading: CircularProgressIndicator.new,
),
FilledButton(
child: const Text('Add .call'),
onPressed: () {
final notifier = ref.read(todosProvider.notifier);
addTodo(
notifier.addTodo(),
mounted: () => context.mounted,
);
},
),
FilledButton(
child: const Text('Add .mutate'),
onPressed: () async {
final notifier = ref.read(todosProvider.notifier);
await addTodo.mutate(
notifier.addTodo(),
mounted: () => context.mounted,
loading: Navigator.of(context).pop,
data: (data) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Todo added: ${data.title}'),
),
);
},
error: (error, stackTrace) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error: $error'),
),
);
},
);
},
),
],
),
);
}
}
Documentation
更多详细信息,请查看文档。
Contributing
欢迎贡献!如果你发现任何问题或有建议,请创建一个新的issue或提交一个pull request。
License
本项目采用MIT License授权。
更多关于Flutter状态管理插件riverpod_hook_mutation的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter状态管理插件riverpod_hook_mutation的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何使用 riverpod_hook_mutation
进行状态管理的 Flutter 代码示例。riverpod_hook_mutation
是一个结合 Riverpod 和 Flutter Hooks 的状态管理插件,它使得状态管理更加简洁和直观。
首先,确保你已经在 pubspec.yaml
文件中添加了必要的依赖:
dependencies:
flutter:
sdk: flutter
flutter_hooks: ^0.18.0 # 请检查最新版本
flutter_riverpod: ^1.0.0 # 请检查最新版本
riverpod_hook_mutation: ^0.1.0 # 请检查最新版本
然后,运行 flutter pub get
来安装这些依赖。
接下来,我们来看一个完整的示例代码:
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_hook_mutation/riverpod_hook_mutation.dart';
void main() {
runApp(
ProviderScope(
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends HookWidget {
final counterProvider = StateProvider<int>((ref) => 0);
@override
Widget build(BuildContext context) {
final counter = useProvider(counterProvider.state);
final mutation = useMutation(counterProvider);
return Scaffold(
appBar: AppBar(
title: Text('Riverpod Hook Mutation Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
mutation.mutate((state) => state! + 1);
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
在这个示例中,我们做了以下几件事:
-
定义状态提供者:我们使用
StateProvider
来创建一个管理整数值的提供者counterProvider
。 -
创建主应用:在
MyApp
中,我们使用ProviderScope
来包裹整个应用,这是使用 Riverpod 所必需的。 -
构建主页面:在
MyHomePage
中,我们使用HookWidget
作为基类,这使得我们可以使用 Flutter Hooks。 -
使用状态提供者:通过
useProvider
钩子获取counterProvider
的当前状态。 -
定义并使用 mutation:通过
useMutation
钩子创建一个mutation
,这个mutation
可以用来修改状态。在按钮点击事件中,我们调用mutate
方法,并传入一个更新状态的函数。
这个示例展示了如何使用 riverpod_hook_mutation
来管理一个简单的计数器状态。你可以根据需要扩展这个示例,以管理更复杂的状态。