Flutter依赖注入与状态管理插件riverpod_repo的使用

Flutter依赖注入与状态管理插件riverpod_repo的使用

概述

riverpod_repo 是一个用于生成基于仓库模式(Repository Pattern)的 Riverpod Providers 的代码生成器。仓库模式将数据访问和存储逻辑与应用程序的其他部分分离,提供了一致的数据访问接口。

使用步骤

1. 创建抽象类(仓库接口)

首先定义一个抽象类作为仓库接口:

import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:riverpod_repo/annotations.dart';

part 'data_repo.g.dart';
part 'data_repo.repo.dart';

@riverpodRepo
abstract class RepoData {
  Future<List<String>> getBooks({String search = '', String categoryId = ''});
  Future<List<int>> getTopGenres();
  Future<List<bool>> getTopBooksByGenre(String genreId, {String search = ''});
  Future<List<String>> getCategories({String search = ''});
}

2. 添加 @riverpodRepo 注解

在你的仓库接口类上添加 @riverpodRepo 注解。

3. 添加 part 指令

.g.dart.repo.dart 文件添加 part 指令:

part 'data_repo.g.dart';
part 'data_repo.repo.dart';

4. 在 pubspec.yaml 中添加 riverpod_generator

确保在 pubspec.yaml 中添加 riverpod_generator 依赖:

dependencies:
  riverpod: any
  riverpod_annotation: any

dev_dependencies:
  build_runner: any
  riverpod_generator: any

5. 创建 Provider 来访问仓库实现

创建一个 Provider 来访问仓库的实现:

@Riverpod(keepAlive: true)
RepoData repoData(RepoDataRef ref) => RepoDataImpl();

6. 运行构建器

运行以下命令生成代码:

flutter pub run build_runner build --delete-conflicting-outputs

这将生成如下内容:

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'data_repo.dart';

@riverpod
Future<List<String>> repoDataGetBooks(RepoDataGetBooksRef ref,
    {String search = '', String categoryId = ''}) {
  return ref.watch(repoDataProvider).getBooks(
        search: search,
        categoryId: categoryId,
      );
}

@riverpod
Future<List<int>> repoDataGetTopGenres(
  RepoDataGetTopGenresRef ref,
) {
  return ref.watch(repoDataProvider).getTopGenres();
}

@riverpod
Future<List<bool>> repoDataGetTopBooksByGenre(
    RepoDataGetTopBooksByGenreRef ref, String genreId,
    {String search = ''}) {
  return ref.watch(repoDataProvider).getTopBooksByGenre(
        genreId,
        search: search,
      );
}

@riverpod
Future<List<String>> repoDataGetCategories(RepoDataGetCategoriesRef ref,
    {String search = ''}) {
  return ref.watch(repoDataProvider).getCategories(
        search: search,
      );
}

7. 使用生成的 Provider

你可以在应用中的任何地方使用这些生成的 Provider:

ref.watch(repoDataGetCategoriesProvider).when(
  loading: () => const CircularProgressIndicator(),
  error: (err, stack) => Text('Error: $err'),
  data: (categories) {
    return Text(categories.toString());
  },
);

示例 Demo

完整示例代码

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:riverpod_repo/annotations.dart';

part 'example.g.dart';
part 'example.repo.dart';

void main() {
  runApp(const ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

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

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final categoriesAsyncValue = ref.watch(repoDataGetCategoriesProvider);

    return Scaffold(
      appBar: AppBar(
        title: const Text('Riverpod Repo Example'),
      ),
      body: Center(
        child: categoriesAsyncValue.when(
          loading: () => const CircularProgressIndicator(),
          error: (err, stack) => Text('Error: $err'),
          data: (categories) {
            return ListView.builder(
              itemCount: categories.length,
              itemBuilder: (context, index) {
                return ListTile(
                  title: Text(categories[index]),
                );
              },
            );
          },
        ),
      ),
    );
  }
}

@Riverpod(keepAlive: true)
RepoData repoData(RepoDataRef ref) => RepoDataImpl();

@riverpodRepo
abstract class RepoData {
  Future<List<String>> getBooks({String search = '', String categoryId = ''});
  Future<List<int>> getTopGenres();
  Future<List<bool>> getTopBooksByGenre(String genreId, {String search = ''});
  Future<List<String>> getCategories({String search = ''});
}

class RepoDataImpl implements RepoData {
  @override
  Future<List<String>> getBooks({String search = '', String categoryId = ''}) async {
    // Mock implementation
    await Future.delayed(const Duration(seconds: 1));
    return ['Book1', 'Book2'];
  }

  @override
  Future<List<int>> getTopGenres() async {
    // Mock implementation
    await Future.delayed(const Duration(seconds: 1));
    return [1, 2, 3];
  }

  @override
  Future<List<bool>> getTopBooksByGenre(String genreId, {String search = ''}) async {
    // Mock implementation
    await Future.delayed(const Duration(seconds: 1));
    return [true, false];
  }

  @override
  Future<List<String>> getCategories({String search = ''}) async {
    // Mock implementation
    await Future.delayed(const Duration(seconds: 1));
    return ['Category1', 'Category2'];
  }
}

注意事项

  1. 提供者名称前缀:生成的 Provider 名称会以前缀的形式包含仓库类名。
  2. 仓库类名和为其创建的 Provider 名称应相同。

许可证

该软件遵循 MIT 许可证。

支持

如有问题,请联系 dilan@dilan.me 获取支持和示例应用。


更多关于Flutter依赖注入与状态管理插件riverpod_repo的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter依赖注入与状态管理插件riverpod_repo的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,关于在Flutter中使用riverpod_repo进行依赖注入与状态管理,这里是一个简要的代码示例,展示了如何设置和使用riverpod_reporiverpod_repo是一个结合了riverpodfreezed的库,用于更好地管理应用程序的状态和依赖项。

首先,确保在你的pubspec.yaml文件中添加必要的依赖项:

dependencies:
  flutter:
    sdk: flutter
  flutter_riverpod: ^1.0.0 # 请根据最新版本进行调整
  riverpod_repo: ^0.1.0 # 请根据最新版本进行调整
  freezed_annotation: ^0.15.0 # freezed库用于数据类不可变性

然后,运行flutter pub get来获取这些依赖项。

接下来,我们创建一个简单的仓库(Repo)并使用riverpod进行依赖注入。

1. 创建数据模型

使用freezed创建一个不可变的数据模型。例如,我们有一个简单的用户模型:

// user_model.dart
import 'package:freezed_annotation/freezed_annotation.dart';

part 'user_model.g.dart';

@freezed
class User with _$User {
  const factory User({
    required String id,
    required String name,
  }) = _User;
}

运行flutter pub run build_runner build来生成user_model.g.dart文件。

2. 创建仓库

接下来,我们创建一个仓库来处理用户数据的获取和管理:

// user_repo.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_repo/riverpod_repo.dart';
import 'user_model.dart';

final userProvider = RepoProvider<User>((ref) {
  // 这里可以添加数据获取逻辑,例如从API获取用户数据
  // 为简单起见,这里我们直接返回一个硬编码的用户对象
  return User(id: '1', name: 'John Doe');
});

3. 在UI中使用仓库

现在,我们可以在UI组件中使用userProvider来获取用户数据:

// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'user_repo.dart';

void main() {
  runApp(
    ProviderScope(
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: UserScreen(),
    );
  }
}

class UserScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final user = ref.watch(userProvider);
    return Scaffold(
      appBar: AppBar(
        title: Text('User Info'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('ID: ${user.id}'),
            Text('Name: ${user.name}'),
          ],
        ),
      ),
    );
  }
}

总结

以上代码展示了如何使用riverpod_repo在Flutter应用中实现依赖注入和状态管理。通过定义数据模型、创建仓库以及在UI组件中消费仓库提供的数据,我们可以轻松地管理应用的状态和依赖项。

请注意,这只是一个简单的示例。在实际应用中,你可能会需要更复杂的逻辑来处理数据获取、缓存、错误处理等。riverpod_reporiverpod提供了强大的工具来帮助你实现这些功能。

回到顶部