正在加载,请稍候…

Flutter 高级状态管理:Riverpod 2.0 深度解析

掌握 Flutter 状态管理,深入 Riverpod 2.0,包括代码生成、异步 Provider、从 Provider 迁移以及真实架构模式。

Flutter 高级状态管理:Riverpod 2.0 深度解析

Flutter 高级状态管理:Riverpod 2.0 深度解析

状态管理一直是 Flutter 开发中最受讨论的话题之一。Riverpod 2.0 已成为复杂应用的首选解决方案,提供编译时安全、依赖注入和强大的异步状态处理。

为什么选择 Riverpod 而非 Provider?

Riverpod 解决了 Provider 的几个根本性限制:

  • 无需 BuildContext:Provider 全局声明,随处访问
  • 编译时安全:无效的 Provider 组合在编译时失败
  • 相同类型的多个 Provider:无 Provider.of 冲突
  • 可测试性:在测试中轻松覆盖 Provider
  • DevTools 集成:内置状态检查

Flutter 高级状态管理:Riverpod 2.0 深度解析 插图

使用代码生成设置 Riverpod 2.0

# pubspec.yaml
dependencies:
  flutter_riverpod: ^2.5.0
  riverpod_annotation: ^2.3.0

dev_dependencies:
  riverpod_generator: ^2.4.0
  build_runner: ^2.4.0
  riverpod_lint: ^2.3.0

运行代码生成:

dart run build_runner watch --delete-conflicting-outputs

Riverpod 2.0 核心概念

Riverpod 2.0 配合代码生成使用单一的 @riverpod 注解:

import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'providers.g.dart';

// 简单同步 Provider
@riverpod
String appVersion(AppVersionRef ref) => '2.0.0';

// Future Provider(异步)
@riverpod
Future<List<User>> users(UsersRef ref) async {
  final repository = ref.watch(userRepositoryProvider);
  return repository.fetchAll();
}

// Stream Provider
@riverpod
Stream<List<Message>> messages(MessagesRef ref, {required String roomId}) {
  final repository = ref.watch(messageRepositoryProvider);
  return repository.streamMessages(roomId);
}

// Notifier(替代 ChangeNotifier)
@riverpod
class Counter extends _$Counter {
  @override
  int build() => 0;

  void increment() => state++;
  void decrement() => state--;
  void reset() => state = 0;
}

用于复杂异步状态的 AsyncNotifier

@riverpod
class UserProfile extends _$UserProfile {
  @override
  Future<UserData> build(String userId) async {
    final repository = ref.watch(userRepositoryProvider);
    return repository.fetchUser(userId);
  }

  Future<void> updateName(String newName) async {
    state = AsyncData(state.requireValue.copyWith(name: newName));
    try {
      await ref.read(userRepositoryProvider).updateName(
        userId: state.requireValue.id,
        name: newName,
      );
    } catch (e, stack) {
      state = AsyncError(e, stack);
      ref.invalidateSelf();
    }
  }
}

高级 Provider 模式

Flutter 高级状态管理:Riverpod 2.0 深度解析 插图

Family Provider

@riverpod
Future<Product> product(ProductRef ref, int productId) async {
  final repository = ref.watch(productRepositoryProvider);
  return repository.fetchProduct(productId);
}

// 在 Widget 中使用
class ProductCard extends ConsumerWidget {
  final int productId;
  const ProductCard({required this.productId, super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final productAsync = ref.watch(productProvider(productId));
    return productAsync.when(
      data: (product) => ProductView(product: product),
      loading: () => const ProductSkeleton(),
      error: (e, _) => ErrorCard(message: e.toString()),
    );
  }
}

Provider 依赖与自动释放

@Riverpod(keepAlive: false)
Future<SearchResults> searchResults(
  SearchResultsRef ref,
  String query,
) async {
  final cancelToken = CancelToken();
  ref.onDispose(cancelToken.cancel);

  return ref.read(searchRepositoryProvider).search(
    query: query,
    cancelToken: cancelToken,
  );
}

从 Provider 迁移

迁移前(Provider):

class UserNotifier extends ChangeNotifier {
  UserData? _user;
  bool _loading = false;

  Future<void> loadUser(String id) async {
    _loading = true;
    notifyListeners();
    _user = await UserRepository().fetchUser(id);
    _loading = false;
    notifyListeners();
  }
}

迁移后(Riverpod 2.0):

@riverpod
Future<UserData> user(UserRef ref, String id) async {
  final repository = ref.watch(userRepositoryProvider);
  return repository.fetchUser(id);
}

class UserScreen extends ConsumerWidget {
  final String userId;
  const UserScreen({required this.userId, super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return ref.watch(userProvider(userId)).when(
      data: (user) => UserView(user: user),
      loading: () => const CircularProgressIndicator(),
      error: (e, _) => Text(e.toString()),
    );
  }
}

异步状态处理:刷新与重试

class UserList extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final usersAsync = ref.watch(usersProvider);

    return RefreshIndicator(
      onRefresh: () => ref.refresh(usersProvider.future),
      child: usersAsync.when(
        skipLoadingOnReload: true,
        data: (users) => ListView.builder(
          itemCount: users.length,
          itemBuilder: (_, i) => UserTile(user: users[i]),
        ),
        loading: () => const ShimmerList(),
        error: (e, _) => ErrorView(
          message: e.toString(),
          onRetry: () => ref.invalidate(usersProvider),
        ),
      ),
    );
  }
}

Flutter 高级状态管理:Riverpod 2.0 深度解析 插图

使用 Riverpod 进行测试

void main() {
  test('loads user successfully', () async {
    final container = ProviderContainer(
      overrides: [
        userRepositoryProvider.overrideWith(
          () => MockUserRepository(user: fakeUser),
        ),
      ],
    );
    addTearDown(container.dispose);

    await container.read(userProfileProvider('user-1').future);

    expect(
      container.read(userProfileProvider('user-1')),
      isA<AsyncData<UserData>>()
        .having((d) => d.value.name, 'name', 'Jane Doe'),
    );
  });
}

性能优化:使用 select() 避免不必要的重建

// 仅在 userName 变化时重建,而非其他用户字段
final userName = ref.watch(
  userProfileProvider(userId).select(
    (userAsync) => userAsync.whenData((u) => u.name),
  ),
);

架构:以功能优先配合 Riverpod

lib/
  features/
    auth/
      data/auth_repository.dart
      domain/user.dart
      presentation/
        providers/auth_providers.dart
        screens/login_screen.dart
    products/...
  shared/
    providers/
      dio_provider.dart
      hive_provider.dart

结论

Riverpod 2.0 配合代码生成代表了 Flutter 状态管理的重大飞跃。其编译时安全、强大的异步处理和清晰的依赖注入使其成为生产级 Flutter 应用的正确选择。从 Provider 的迁移路径是渐进式的且文档完善,从简单的计数器扩展到复杂的多功能应用。