ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、视频、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] > [pub home](https://pub.dev/packages/riverpod) > [home](https://riverpod.dev/zh-Hans/docs/migration/from_state_notifier) ## 概述 hooks_riverpod 是结合了 Flutter Hooks 和 Riverpod 的状态管理解决方案,具有以下优点: * 状态管理更清晰,避免setState 的滥用 * 依赖注入更容易,方便测试 * 代码复用性更好 * 性能优化(通过细粒度的重建控制) * 更好的类型安全 * 结合 Hooks的优势,减少模板代码 ## 安装 ``` flutter pub add hooks_riverpod ``` 在项目跟目录配置 ``` void main() { runApp( // To install Riverpod, we need to add this widget above everything else. // This should not be inside "MyApp" but as direct parameter to "runApp". // 为了安装 Riverpod,我们需要将这个小组件添加到所有的小组件之上。 // 它不应该在 “MyApp” 内部,而是作为 “runApp” 的直接参数。 ProviderScope( child: MyApp(), ), ); } ``` ## 语法-无注释版本 安装依赖 ``` ``` ### 常见 Provider 类型 <details> <summary> 实例</summary> ``` // 1. Provider - 最基础的只读数据 final nameProvider = Provider<String>((ref) => '张三'); // 2. StateProvider - 可变状态的简单数据 final counterProvider = StateProvider<int>((ref) => 0); // 3. StateNotifierProvider - 复杂状态管理 class TodoNotifier extends StateNotifier<List<Todo>> { TodoNotifier(): super([]); void addTodo(Todo todo) { state = [...state, todo]; } } final todosProvider = StateNotifierProvider<TodoNotifier, List<Todo>>((ref) { return TodoNotifier(); }); // 4. FutureProvider - 异步数据 final userProvider = FutureProvider<User>((ref) async { return await UserApi.fetchUser(); }); ``` </details> ### Provider 修饰符 <details> <summary>实例</summary> ``` // 1. select - 部分监听 final value = ref.watch(provider.select((data) => data.specific)); // 2. family - 参数化 provider final userProvider = FutureProvider.family<User, String>((ref, userId) async { return await UserApi.fetchUser(userId); }); // 使用 final user = ref.watch(userProvider('123')); ``` </details> ### 在 Widget 中使用 Consumer <details> <summary>实例</summary> ``` /// 我们应用程序主页 class Home extends StatelessWidget { const Home({super.key}); @override Widget build(BuildContext context) { return Consumer( builder: (context, ref, child) { // 读取 activityProvider。如果没有准备开始,这将会开始一个网络请求。 // 通过使用 ref.watch,小组件将会在 activityProvider 更新时重建。 // 当下面的事情发生时,会更新小组件: // - 响应从“正在加载”变为“数据/错误” // - 请求重刷新 // - 结果被本地修改(例如执行副作用时) // ... final AsyncValue<Activity> activity = ref.watch(activityProvider); return Center( /// 由于网络请求是异步的并且可能会失败,我们需要处理错误和加载的状态。 /// 我们可以为此使用模式匹配。 /// 我们也可以使用 `if (activity.isLoading) { ... } else if (...)` child: switch (activity) { AsyncData(:final value) => Text('Activity: ${value.activity}'), AsyncError() => const Text('Oops, something unexpected happened'), _ => const CircularProgressIndicator(), }, ); }, ); } } ``` </details> HookConsumerWidget <details> <summary>实例</summary> ``` // 使用 HookConsumerWidget class MyWidget extends HookConsumerWidget { const MyWidget({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { // 读取数据 final name = ref.watch(nameProvider); // 获取状态控制器 final counter = ref.watch(counterProvider.notifier); // 使用 hooks final textController = useTextEditingController(); return Column( children: [ Text(name), ElevatedButton( onPressed: () => counter.state++, child: Text('计数: ${counter.state}'), ), ], ); } } ``` </details> ## 语法带注释版本 ``` flutter pub add hooks_riverpod flutter pub add flutter_hooks flutter pub add riverpod_annotation flutter pub add dev:riverpod_generator flutter pub add dev:build_runner flutter pub add dev:custom_lint flutter pub add dev:riverpod_lint ``` ## 实例 ### 网络请求 <details> <summary>实例</summary> ``` import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'dart:async'; // 模拟成功的网络请求 final successProvider = FutureProvider<String>((ref) async { // 模拟网络延迟 await Future.delayed(const Duration(seconds: 2)); return '请求成功,获取到数据!'; }); // 模拟失败的网络请求 final failureProvider = FutureProvider<String>((ref) async { // 模拟网络延迟 await Future.delayed(const Duration(seconds: 2)); throw Exception('网络请求失败!'); }); class RiverpodNetwork extends ConsumerWidget { const RiverpodNetwork({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final successRequest = ref.watch(successProvider); final failureRequest = ref.watch(failureProvider); return Scaffold( appBar: AppBar( title: const Text('Riverpod 网络请求示例'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 成功请求的展示 successRequest.when( data: (data) => Text(data), error: (error, stack) => Text('错误: $error'), loading: () => const CircularProgressIndicator(), ), const SizedBox(height: 20), // 失败请求的展示 failureRequest.when( data: (data) => Text(data), error: (error, stack) => Text('错误: $error'), loading: () => const CircularProgressIndicator(), ), ], ), ), ); } } ``` </details>