Riverpod:如何在AsyncNotifier构造函数中获取ref(Retrofit分页场景)
解决Retrofit+Riverpod分页Notifier无法访问ref获取Repository的问题
这里有几种可行的方案,根据你的代码结构选择合适的:
方案1:在Provider创建时传递Repository的分页方法
这种方式最简洁,把分页API的调用逻辑封装成方法,在Provider初始化Notifier时通过ref拿到Repository,再把方法传给基类构造函数。
步骤:
- 定义通用的
PaginationNotifier基类,构造函数接收分页请求方法:
abstract class PaginationNotifier<T> extends StateNotifier<PaginationState<T>> { final Future<List<T>> Function(int page) fetchPage; PaginationNotifier(this.fetchPage) : super(PaginationState.initial()); // 通用分页逻辑:加载下一页 Future<void> loadNextPage() async { if (state.isLoading) return; state = state.copyWith(isLoading: true); try { final nextPage = state.currentPage + 1; final data = await fetchPage(nextPage); if (data.isEmpty) { state = state.copyWith(hasReachedEnd: true, isLoading: false); } else { state = state.copyWith( items: [...state.items, ...data], currentPage: nextPage, isLoading: false, ); } } catch (e) { state = state.copyWith(isLoading: false, error: e.toString()); } } }
- 子类
UserNotifier直接继承基类,无需处理ref:
class UserNotifier extends PaginationNotifier<User> { UserNotifier(super.fetchPage); }
- 在Provider中通过ref获取
ApiRepository,并传递分页方法:
final userNotifierProvider = StateNotifierProvider<UserNotifier, PaginationState<User>>((ref) { final apiRepo = ref.watch(apiRepositoryProvider); // 把repo的分页方法传递给UserNotifier return UserNotifier((page) => apiRepo.fetchUsers(page: page)); });
方案2:让基类持有Ref,子类实现具体分页逻辑
如果需要在基类中访问更多Riverpod依赖,或者希望子类更灵活地控制API调用,可以让基类持有Ref实例。
步骤:
- 修改
PaginationNotifier基类,接收Ref:
abstract class PaginationNotifier<T> extends StateNotifier<PaginationState<T>> { final Ref ref; PaginationNotifier(this.ref) : super(PaginationState.initial()); // 子类必须实现的分页请求方法 Future<List<T>> fetchPage(int page); // 通用分页逻辑(和方案1一致) Future<void> loadNextPage() async { if (state.isLoading) return; state = state.copyWith(isLoading: true); try { final nextPage = state.currentPage + 1; final data = await fetchPage(nextPage); if (data.isEmpty) { state = state.copyWith(hasReachedEnd: true, isLoading: false); } else { state = state.copyWith( items: [...state.items, ...data], currentPage: nextPage, isLoading: false, ); } } catch (e) { state = state.copyWith(isLoading: false, error: e.toString()); } } }
- 子类
UserNotifier通过ref获取Repository并实现分页方法:
class UserNotifier extends PaginationNotifier<User> { UserNotifier(super.ref); @override Future<List<User>> fetchPage(int page) { // 直接通过ref获取ApiRepository并调用方法 return ref.watch(apiRepositoryProvider).fetchUsers(page: page); } }
- Provider初始化时传递ref:
final userNotifierProvider = StateNotifierProvider<UserNotifier, PaginationState<User>>((ref) { return UserNotifier(ref); });
方案3:传递Repository实例给子类
如果需要在子类中直接操作Repository的其他方法,可以把Repository实例直接传给基类或子类。
示例:
abstract class PaginationNotifier<T> extends StateNotifier<PaginationState<T>> { final ApiRepository repo; PaginationNotifier(this.repo) : super(PaginationState.initial()); // 子类实现具体的分页调用 Future<List<T>> fetchPage(int page); // 通用分页逻辑... } class UserNotifier extends PaginationNotifier<User> { UserNotifier(super.repo); @override Future<List<User>> fetchPage(int page) { return repo.fetchUsers(page: page); } } // Provider定义 final userNotifierProvider = StateNotifierProvider<UserNotifier, PaginationState<User>>((ref) { final repo = ref.watch(apiRepositoryProvider); return UserNotifier(repo); });
核心思路:Riverpod中StateNotifier的构造函数无法直接获取ref,必须在StateNotifierProvider的创建回调中通过ref拿到依赖,再传递给Notifier的构造函数。以上三种方案都是基于这个核心逻辑,根据你的复用需求和代码复杂度选择即可。
内容的提问来源于stack exchange,提问作者silvershort
相关产品推荐
相关产品推荐

