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渲染)
相关推荐
一起养小猫7 分钟前
Flutter for OpenHarmony 实战:记忆翻牌游戏完整开发指南
flutter·游戏·harmonyos
lbb 小魔仙18 分钟前
【HarmonyOS】DAY13:Flutter电商实战:从零开发注册页面(含密码验证、确认密码完整实现)
flutter·华为·harmonyos
晚霞的不甘36 分钟前
Flutter for OpenHarmony 豪华抽奖应用:从粒子背景到彩带动画的全栈实现
前端·学习·flutter·microsoft·前端框架
铅笔侠_小龙虾1 小时前
浅谈 Vue & React & Flutter 框架
vue.js·flutter·react.js
日光倾1 小时前
【Vue.js 入门笔记】 状态管理器Vuex
vue.js·笔记·flutter
一起养小猫11 小时前
Flutter for OpenHarmony 进阶:体育计分系统与数据持久化深度解析
flutter·harmonyos
ujainu12 小时前
Flutter + OpenHarmony 游戏开发进阶:主菜单架构与历史最高分持久化
flutter·游戏·架构·openharmony
铅笔侠_小龙虾13 小时前
Flutter Demo
开发语言·javascript·flutter
2501_9445255413 小时前
Flutter for OpenHarmony 个人理财管理App实战 - 账户详情页面
android·java·开发语言·前端·javascript·flutter
2601_9498574313 小时前
Flutter for OpenHarmony Web开发助手App实战:快捷键参考
前端·flutter