Flutter 列表 + Riverpod 架构实战 —— 从 setState 到状态驱动列表的工程落地

Flutter 列表真正的威力,不在 ListView,而在:

👉 列表 = 状态的投影结果


一、为什么 Flutter 列表必须配状态管理?

新手写法:

Dart 复制代码
setState(() {
  list.addAll(newData);
});

问题:

  • 业务逻辑混在 UI
  • 无法复用
  • 无法测试
  • 分页、错误、加载状态混乱

企业级目标:

👉 UI 只关心"状态"

👉 所有列表行为 = 状态机

二、列表的标准状态建模(架构核心)

一个工程级列表,最少包含:

Dart 复制代码
class ListState<T> {
  final List<T> items;
  final bool isLoading;
  final bool isRefreshing;
  final bool hasMore;
  final String? error;

  const ListState({
    this.items = const [],
    this.isLoading = false,
    this.isRefreshing = false,
    this.hasMore = true,
    this.error,
  });
}

👉 这是 Flutter 列表的"领域模型(Domain State)"。

三、Riverpod Controller 层(替代 ViewModel)

Dart 复制代码
class UserListController extends StateNotifier<ListState<User>> {
  UserListController() : super(const ListState());

  Future<void> refresh() async {
    state = state.copyWith(isRefreshing: true);
    final data = await repo.fetch(page: 1);
    state = state.copyWith(
      items: data,
      isRefreshing: false,
      hasMore: true,
    );
  }

  Future<void> loadMore() async {
    if (!state.hasMore || state.isLoading) return;

    state = state.copyWith(isLoading: true);
    final data = await repo.fetchNext();
    state = state.copyWith(
      items: [...state.items, ...data],
      isLoading: false,
      hasMore: data.isNotEmpty,
    );
  }
}
Dart 复制代码
final userListProvider =
  StateNotifierProvider<UserListController, ListState<User>>(
    (ref) => UserListController(),
  );

👉 这里就是 MVVM / MVI 的 ViewModel / Reducer 层。

四、UI 层(纯渲染,不写业务)

Dart 复制代码
class UserListPage extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final state = ref.watch(userListProvider);
    final controller = ref.read(userListProvider.notifier);

    return RefreshIndicator(
      onRefresh: controller.refresh,
      child: ListView.builder(
        itemCount: state.items.length + 1,
        itemBuilder: (context, index) {
          if (index == state.items.length) {
            return _Footer(state);
          }
          return UserItem(state.items[index]);
        },
      ),
    );
  }
}
Dart 复制代码
class _Footer extends StatelessWidget {
  final ListState state;

  const _Footer(this.state);

  @override
  Widget build(BuildContext context) {
    if (state.isLoading) {
      return Center(child: CircularProgressIndicator());
    }
    if (!state.hasMore) {
      return Center(child: Text("没有更多了"));
    }
    return SizedBox.shrink();
  }
}

✔ UI = 纯函数

✔ 可测试

✔ 可替换

✔ 可维护

五、滚动触底触发分页

Dart 复制代码
final scrollController = ScrollController();

scrollController.addListener(() {
  if (scrollController.position.pixels >
      scrollController.position.maxScrollExtent - 200) {
    ref.read(userListProvider.notifier).loadMore();
  }
});

👉 滚动是输入

👉 Controller 决定状态变化

👉 UI 只是结果

六、这套架构解决了什么?

问题 解决
setState 混乱 状态集中管理
分页难写 行为模型化
异常难处理 error 状态
UI 不可测 Controller 可单测
列表难复用 Domain State 可复用

👉 这是"架构级列表"。

七、架构总结

Flutter 列表的终极形式:

Dart 复制代码
Input(滚动/点击)
   ↓
Controller(Riverpod)
   ↓
State(列表领域模型)
   ↓
ListView(UI渲染)
相关推荐
忆江南8 小时前
iOS 深度解析
flutter·ios
明君879979 小时前
Flutter 实现 AI 聊天页面 —— 记一次 Markdown 数学公式显示的踩坑之旅
前端·flutter
恋猫de小郭10 小时前
移动端开发稳了?AI 目前还无法取代客户端开发,小红书的论文告诉你数据
前端·flutter·ai编程
MakeZero12 小时前
Flutter那些事-交互式组件
flutter
shankss13 小时前
pull_to_refresh_simple
flutter
shankss13 小时前
Flutter 下拉刷新库新特性:智能预加载 (enableSmartPreload) 详解
flutter
SoaringHeart2 天前
Flutter调试组件:打印任意组件尺寸位置信息 NRenderBox
前端·flutter
九狼2 天前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
_squirrel2 天前
记录一次 Flutter 升级遇到的问题
flutter
Haha_bj2 天前
Flutter——状态管理 Provider 详解
flutter·app