跳到主要内容

ChangeNotifierProvider

ChangeNotifierProvider (来自 flutter_riverpod/hooks_riverpod) 是一个用于监听和暴露Flutter本身的 ChangeNotifier 的provider。

Riverpod不鼓励使用 ChangeNotifierProvider ,它的存在主要是为了:

  • an easy transition from package:provider when using its ChangeNotifierProvider
  • 当使用它的 ChangeNotifierProvider 时,简单地从 package:provider 迁移。
  • 支持可变状态,即使不可变的状态更好。
信息

更倾向于使用 StateNotifierProvider。 只有在绝对需要可变状态时才考虑使用 ChangeNotifierProvider

使用可变状态而不是不可变状态有时会更高效。 但缺点是它可能更难维护,并可能破坏各种功能。
比如说如果状态是可变的, 用于优化widget重新构建的 provider.select 可能不起作用, 因为Select会认为值没有改变。
因此,使用不可变的数据结构有时会更快。 制定特定用例的基准测试非常重要,以确保通过使用 ChangeNotifierProvider 时能真正获得性能。

下面是用法示例,我们可以使用 ChangeNotifierProvider 来实现待办清单。 这样做将允许我们公开 addTodo 等方法,让UI修改用户交互中的待办清单:


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>[];

// Let's allow the UI to add todos.
void addTodo(Todo todo) {
todos.add(todo);
notifyListeners();
}

// Let's allow removing todos
void removeTodo(String todoId) {
todos.remove(todos.firstWhere((element) => element.id == todoId));
notifyListeners();
}

// Let's mark a todo as completed
void toggle(String todoId) {
final todo = todos.firstWhere((todo) => todo.id == todoId);
todo.completed = !todo.completed;
notifyListeners();
}
}

// Finally, we are using ChangeNotifierProvider to allow the UI to interact with
// our TodosNotifier class.
final todosProvider = ChangeNotifierProvider<TodosNotifier>((ref) {
return TodosNotifier();
});

现在我们已经定义了一个 ChangeNotifierProvider, 我们可以用它来与UI中的待办清单交互:


class TodoListView extends ConsumerWidget {
const TodoListView({super.key});


Widget build(BuildContext context, WidgetRef ref) {
// rebuild the widget when the todo list changes
List<Todo> todos = ref.watch(todosProvider).todos;

// Let's render the todos in a scrollable list view
return ListView(
children: [
for (final todo in todos)
CheckboxListTile(
value: todo.completed,
// When tapping on the todo, change its completed status
onChanged: (value) =>
ref.read(todosProvider.notifier).toggle(todo.id),
title: Text(todo.description),
),
],
);
}
}