Riverpod的官方文档有多国语言,但是没有汉语,所以个人简单翻译了一版。
官网文档:Riverpod
GitHub:GitHub - rrousselGit/river_pod
Pub:riverpod | Dart Package (flutter-io.cn)
译时版本:riverpod 1.0.3
ChangeNotifierProvider
ChangeNotifierProvider
(仅用于 flutter_riverpod/hooks_riverpod)是用于Flutter 自身监听和暴露 ChangeNotifier 的 Provider 。
Riverpod 不建议使用 ChangeNotifierProvider
,只为以下几种情况保留:
- 使用
package:provider
的ChangeNotifierProvider
进行简单过滤时。 - 支持可变状态,即使不可变状态更好用。
信息
更倾向于使用 StateNotifierProvider 代替 只在绝对确定想要使用可变状态时考虑使用ChangeNotifierProvider
。
有时使用可变状态代替不可变状态会更高效。 副作用是,难于维护,并可能破坏各种功能。
例如,如果状态可变,使用 provider.select
改善组件的重新构建时可能不起作用,因为 select
会认为值没有改变。
就此而论,使用不可变数据结构有时会更快。
因此,为使用场景创建性能指标很重要,要确保通过使用 ChangeNotifierProvider
确实能提高性能。
作为用法示例,我们使用 ChangeNotifierProvider
实现了一个 todo 列表。
这样做允许我们暴露 如 addTodo
的方法使 UI 在用户交互时改变 todo 列表:
class Todo {
Todo({
required this.id,
required this.description,
required this.completed,
});
String id;
String description;
bool completed;
}
class TodosNotifier extends ChangeNotifier {
final todos = <Todo>[];
// 让 UI 添加 todo
void addTodo(Todo todo) {
todos.add(todo);
notifyListeners();
}
// 可移除 todo
void removeTodo(String todoId) {
todos.remove(todos.firstWhere((element) => element.id == todoId));
notifyListeners();
}
// 标记 todo 为完成
void toggle(String todoId) {
for (final todo in todos) {
if (todo.id == todoId) {
todo.completed = !todo.completed;
notifyListeners();
}
}
}
}
// 最终,使用 StateNotifierProvider 允许 UI 和 TodosNotifier 类交互。
final todosProvider = ChangeNotifierProvider<TodosNotifier>((ref) {
return TodosNotifier();
});
现在我们已经定义了 ChangeNotifierProvider
,我们可以在 UI 中用其和 todo 列表交互:
class TodoListView extends ConsumerWidget {
const TodoListView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
// todo 列表改变时重新构建组件
List<Todo> todos = ref.watch(todosProvider).todos;
// 在可滚动的列表视图中渲染 todo
return ListView(
children: [
for (final todo in todos)
CheckboxListTile(
value: todo.completed,
// 点击 todo 时,改变完成状态
onChanged: (value) =>
ref.read(todosProvider.notifier).toggle(todo.id),
title: Text(todo.description),
),
],
);
}
}