You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Riverpod:如何在AsyncNotifier构造函数中获取ref(Retrofit分页场景)

解决Retrofit+Riverpod分页Notifier无法访问ref获取Repository的问题

这里有几种可行的方案,根据你的代码结构选择合适的:

方案1:在Provider创建时传递Repository的分页方法

这种方式最简洁,把分页API的调用逻辑封装成方法,在Provider初始化Notifier时通过ref拿到Repository,再把方法传给基类构造函数。

步骤:

  1. 定义通用的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());
    }
  }
}
  1. 子类UserNotifier直接继承基类,无需处理ref:
class UserNotifier extends PaginationNotifier<User> {
  UserNotifier(super.fetchPage);
}
  1. 在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实例。

步骤:

  1. 修改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());
    }
  }
}
  1. 子类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);
  }
}
  1. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 10:21:13