Riverpod
作用:Flutter 中更现代、更类型安全的响应式状态管理库。
-
ProviderScope
根节点用
ProviderScope包裹void main() { runApp( const ProviderScope( child: MyApp(), ), ); }
provider相关
- provider
Provider 适合放 只读依赖 或 计算值。
/// 声明
final apiClientProvider = Provider<ApiClient>((ref) {
return ApiClient();
});
/// 使用
final apiClient = ref.watch(apiClientProvider);
- StateProvider
适合非常简单的局部状态,比如开关、计数器、Tab 下标、输入框临时值。
final selectedTabProvider = StateProvider<int>((ref) => 0);
final isDarkModeProvider = StateProvider<bool>((ref) => false);
final keywordProvider = StateProvider<String>((ref) => '');
- FutureProvider
FutureProvider 适合 只读异步数据,比如页面初始化时请求接口。
通常用于:
- 获取用户信息
- 获取配置
- 获取列表等
/// 声明
final userProvider = FutureProvider<User>((ref) async {
final repository = ref.watch(userRepositoryProvider);
return repository.getUser();
});
/// 使用
final userAsync = ref.watch(userProvider);
return userAsync.when(
data: (user) => Text(user.name),
loading: () => const CircularProgressIndicator(),
error: (error, stack) => Text('加载失败: $error'),
);
- StreamProvider
StreamProvider 适合监听持续变化的数据。
适用于:
- WebSocket
- 本地数据库监听
- 实时消息
- 倒计时
final messageStreamProvider = StreamProvider<List<Message>>((ref) {
final repository = ref.watch(messageRepositoryProvider);
return repository.watchMessages();
});
NotifierProvider&AsyncNotifierProvider&StateNotifierProvider
- NotifierProvider
适合管理同步业务状态,比如购物车、本地筛选条件、主题、表单状态、登录态缓存等。
/// 定义
final themeControllerProvider =
NotifierProvider<ThemeController, ThemeMode>(ThemeController.new);
class ThemeController extends Notifier<ThemeMode> {
@override
ThemeMode build() {
return ThemeMode.system;
}
void setThemeMode(ThemeMode mode) {
state = mode;
}
void toggleDarkMode() {
state = state == ThemeMode.dark ? ThemeMode.light : ThemeMode.dark;
}
}
/// 使用
final themeMode = ref.watch(themeControllerProvider);
MaterialApp(
themeMode: themeMode,
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
);
ref.read(themeControllerProvider.notifier).toggleDarkMode();
- AsyncNotifierProvider
用户列表、房间列表、商品列表、添加、删除、更新、刷新等任何与后台相关的数据
/// 声明
final userListProvider =
AsyncNotifierProvider<UserListController, List<User>>(
UserListController.new,
);
class UserListController extends AsyncNotifier<List<User>> {
late final UserRepository _repository;
@override
Future<List<User>> build() async {
_repository = ref.watch(userRepositoryProvider);
return _repository.fetchUsers();
}
Future<void> refresh() async {
state = const AsyncLoading();
state = await AsyncValue.guard(() async {
return _repository.fetchUsers();
});
}
Future<void> deleteUser(String userId) async {
await _repository.deleteUser(userId);
final currentUsers = state.valueOrNull ?? [];
state = AsyncData(
currentUsers.where((user) => user.id != userId).toList(),
);
}
}
/// 使用
final usersAsync = ref.watch(userListProvider);
return usersAsync.when(
data: (users) {
return ListView.builder(
itemCount: users.length,
itemBuilder: (_, index) {
final user = users[index];
return ListTile(
title: Text(user.name),
trailing: IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
ref.read(userListProvider.notifier).deleteUser(user.id);
},
),
);
},
);
},
loading: () => const CircularProgressIndicator(),
error: (error, stack) => Text('加载失败: $error'),
);
- StateNotifierProvider
老版本的写法,将状态与模型一起管理,在内部实现状态的更新。
final userProvider =
StateNotifierProvider<UserNotifier, AsyncValue<User>>((ref) {
final repository = ref.watch(userRepositoryProvider);
return UserNotifier(repository);
});
class UserNotifier extends StateNotifier<AsyncValue<User>> {
UserNotifier(this._repository) : super(const AsyncLoading()) {
load();
}
final UserRepository _repository;
Future<void> load() async {
state = await AsyncValue.guard(() {
return _repository.getUser();
});
}
}
ConsumerWidget & ConsumerStatefulWidget
- ConsumerWidget
适合无本地生命周期逻辑的页面。
class UserPage extends ConsumerWidget {
const UserPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final usersAsync = ref.watch(userListProvider);
return usersAsync.when(
data: (users) => Text('用户数: ${users.length}'),
loading: () => const CircularProgressIndicator(),
error: (error, stack) => Text('错误: $error'),
);
}
}
- ConsumerStatefulWidget
适合需要 initState、dispose、TabController、AnimationController 的页面。
class UserPage extends ConsumerStatefulWidget {
const UserPage({super.key});
@override
ConsumerState<UserPage> createState() => _UserPageState();
}
class _UserPageState extends ConsumerState<UserPage> {
@override
void initState() {
super.initState();
Future.microtask(() {
ref.read(userListProvider.notifier).refresh();
});
}
@override
Widget build(BuildContext context) {
final usersAsync = ref.watch(userListProvider);
return usersAsync.when(
data: (users) => Text('用户数: ${users.length}'),
loading: () => const CircularProgressIndicator(),
error: (error, stack) => Text('错误: $error'),
);
}
}
ref.watch / ref.read / ref.listen
1. ref.watch
用于 监听状态变化并重建 UI。
final count = ref.watch(counterProvider);
适合写在 build 中。
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Text('$count');
}
只要 counterProvider 变化,当前 Widget 会重新 build。
2. ref.read
用于 读取一次状态,不监听变化。
常用于按钮点击、事件回调。
onPressed: () {
ref.read(counterProvider.notifier).state++;
}
不建议在 build 中大量使用 read 来获取 UI 数据,因为它不会自动刷新页面。
3. ref.listen
用于 监听状态变化并执行副作用。
比如弹 Toast、跳转页面、显示 Dialog。
ref.listen(authControllerProvider, (previous, next) {
if (next.hasError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('登录失败')),
);
}
});
family:带参数的 Provider
family 用于根据参数创建不同的 Provider 实例。根据筛选条件查询:
/// 声明
final userDetailProvider = FutureProvider.family<User, String>((ref, userId) {
final repository = ref.watch(userRepositoryProvider);
return repository.getUserDetail(userId);
});
/// 使用
final userAsync = ref.watch(userDetailProvider(userId));
autoDispose / keepAlive
autoDispose 表示没有页面监听时,Provider 会自动释放。
在新版代码生成方式中,默认经常是自动释放;需要长期缓存时可以配置 keepAlive。
适合自动释放:
| 场景 |
|---|
| 详情页数据 |
| 搜索结果 |
| 临时筛选条件 |
| 页面级状态 |
适合 keepAlive:
| 场景 |
|---|
| 登录用户信息 |
| 全局配置 |
| 主题设置 |
| Token 管理 |
| App 初始化状态 |
使用注解时:
@Riverpod(keepAlive: true)
class AuthController extends _$AuthController {
@override
Future<User?> build() async {
return getCurrentUser();
}
}
代码生成方式:@riverpod
flutter pub add flutter_riverpod riverpod_annotation
flutter pub add dev:build_runner dev:riverpod_generator
添加了注解后的写法可以变成
@riverpod
class UserListController extends _$UserListController {
@override
Future<List<User>> build() async {
final repository = ref.watch(userRepositoryProvider);
return repository.fetchUsers();
}
Future<void> refresh() async {
final repository = ref.read(userRepositoryProvider);
state = const AsyncLoading();
state = await AsyncValue.guard(() async {
return repository.fetchUsers();
});
}
Future<void> deleteUser(String userId) async {
final repository = ref.read(userRepositoryProvider);
final previousUsers = state.valueOrNull ?? [];
state = AsyncData(
previousUsers.where((user) => user.id != userId).toList(),
);
try {
await repository.deleteUser(userId);
} catch (error, stackTrace) {
state = AsyncError(error, stackTrace);
}
}
}