Flutter 状态复杂度,如何在架构层提前“刹车”



子玥酱 (掘金 / 知乎 / CSDN / 简书 同名)

大家好,我是 子玥酱,一名长期深耕在一线的前端程序媛 👩‍💻。曾就职于多家知名互联网大厂,目前在某国企负责前端软件研发相关工作,主要聚焦于业务型系统的工程化建设与长期维护。

我持续输出和沉淀前端领域的实战经验,日常关注并分享的技术方向包括 前端工程化、小程序、React / RN、Flutter、跨端方案,

在复杂业务落地、组件抽象、性能优化以及多端协作方面积累了大量真实项目经验。

技术方向: 前端 / 跨端 / 小程序 / 移动端工程化 内容平台: 掘金、知乎、CSDN、简书 创作特点: 实战导向、源码拆解、少空谈多落地 **文章状态:**长期稳定更新,大量原创输出

我的内容主要围绕 前端技术实战、真实业务踩坑总结、框架与方案选型思考、行业趋势解读 展开。文章不会停留在"API 怎么用",而是更关注为什么这么设计、在什么场景下容易踩坑、真实项目中如何取舍,希望能帮你在实际工作中少走弯路。

子玥酱 · 前端成长记录官 ✨

👋 如果你正在做前端,或准备长期走前端这条路

📚 关注我,第一时间获取前端行业趋势与实践总结

🎁 可领取 11 类前端进阶学习资源 (工程化 / 框架 / 跨端 / 面试 / 架构)

💡 一起把技术学"明白",也用"到位"

持续写作,持续进阶。

愿我们都能在代码和生活里,走得更稳一点 🌱

文章目录

引言

很多 Flutter 项目,不是一开始就乱的

刚启动的时候,结构清晰、状态不多、页面逻辑简单,大家都觉得 Flutter 写起来挺爽。

但过一段时间你会发现:

  • Provider 越加越多
  • 页面逻辑越来越厚
  • 一个需求改动,牵一堆地方

最后大家会下意识地把锅甩给一句话:

Flutter 的状态管理太乱了。

但如果你回头复盘,大多数问题并不是状态管理框架选错了,而是:

架构层从一开始,就没有给"状态复杂度"留刹车空间。

状态复杂度不是突然爆炸的,而是"慢慢失控"的

页面状态写在 Widget 里

dart 复制代码
class ProductPage extends StatefulWidget {
  @override
  State<ProductPage> createState() => _ProductPageState();
}

class _ProductPageState extends State<ProductPage> {
  bool loading = false;
  List<String> products = [];

  Future<void> loadData() async {
    setState(() => loading = true);
    await Future.delayed(Duration(seconds: 1));
    setState(() {
      products = ['Apple', 'Banana'];
      loading = false;
    });
  }
}

一切看起来都很合理

状态开始被多个地方使用

  • 列表页要用
  • 详情页要用
  • 刷新、分页、筛选都要用

于是你做了第一步"优化":

把状态提取到 Provider / Riverpod 里。

状态集中,但复杂度没降

dart 复制代码
class ProductState extends ChangeNotifier {
  bool loading = false;
  List<String> products = [];
  String keyword = '';
  int page = 1;

  Future<void> load() async {
    loading = true;
    notifyListeners();
    await Future.delayed(Duration(seconds: 1));
    products.addAll(['Apple', 'Banana']);
    loading = false;
    notifyListeners();
  }
}

看起来状态"集中"了,但你很快会发现:

  • 所有页面都在监听这个 State
  • 一点小变动,整个页面树都在 rebuild
  • 状态文件越来越像一个"垃圾桶"

这一步,才是大多数 Flutter 项目真正开始失控的地方。

问题不在"状态放哪",而在"状态边界"

Flutter 的状态复杂度,本质上不是数量问题,而是边界问题

一个很关键但常被忽略的问题

这个状态,生命周期到底有多长?

如果你不在架构层回答这个问题,后面一定会付出代价。

一个简单但非常有效的"状态生命周期划分法"

UI 临时状态

  • loading 动画开关
  • tab index
  • checkbox 勾选

原则:离 UI 越近越好

dart 复制代码
bool _loading = false;

页面级状态

  • 列表数据
  • 表单内容
  • 页面筛选条件

只服务于一个页面或一个功能域

全局状态

  • 登录态
  • 用户信息
  • 系统配置

必须极少、极稳、极慎重

很多 Flutter 项目"炸",就是因为把页面状态当成了全局状态。

禁止"状态无理由上提"

一个非常重要的架构原则:

状态不应该因为"方便",就被提升到更高层级。

错误示例:页面状态直接全局化

dart 复制代码
final productProvider = ChangeNotifierProvider(
  create: (_) => ProductState(),
);

然后所有页面都 watch 它。

这在前期看起来很爽,但后期会带来两个问题:

  1. rebuild 范围不可控
  2. 状态职责开始模糊

正确做法:状态按功能域隔离

dart 复制代码
class ProductModule extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) => ProductState(),
      child: ProductPage(),
    );
  }
}
  • 状态跟着功能走
  • 页面销毁,状态一起销毁
  • 不给复杂度"扩散"的机会

是 Flutter 架构中非常重要的一脚刹车。

UI 不直接"写业务状态"

很多 Flutter 项目后期难维护,是因为 UI 层承担了太多职责。

反面示例

dart 复制代码
onPressed: () async {
  state.loading = true;
  notifyListeners();
  await api.fetch();
  state.products.addAll(result);
  state.loading = false;
  notifyListeners();
}

UI 知道太多了。

正确做法:状态自己对外暴露"意图"

dart 复制代码
class ProductState extends ChangeNotifier {
  Future<void> refresh() async {
    _setLoading(true);
    await _loadData();
    _setLoading(false);
  }
}

UI 只做一件事:

dart 复制代码
onPressed: state.refresh

UI 只表达"我要做什么",

不关心"你是怎么做的"。

防止状态"越管越大"

一个非常实用的判断标准:

如果一个 State 文件开始超过 300 行,基本已经失控。

这时你需要做的不是换框架,而是拆状态

拆分示例

dart 复制代码
class ProductListState {}
class ProductFilterState {}
class ProductPagingState {}

再由一个组合层统一协调。

dart 复制代码
class ProductViewModel {
  final list = ProductListState();
  final filter = ProductFilterState();
}

本质上和前端拆 reducer、iOS 拆 ViewModel 是一回事。

为什么 iOS 项目"看起来更稳"?

因为 UIKit / MVC 帮你强制做了很多刹车

  • 页面生命周期固定
  • Controller 天然是边界
  • 状态默认不跨页面

而 Flutter / 前端给了你极大的自由,但不会替你踩刹车。

一套真正"抗演进"的 Flutter 状态架构原则

如果你只记住这一段就够了:

  1. 状态永远有生命周期
  2. 生命周期决定状态归属
  3. 页面状态默认不全局
  4. UI 不写业务流程
  5. 复杂不是错,失控才是错

总结

Flutter 状态管理真正难的地方,从来不是:

Provider 还是 Riverpod?

Bloc 会不会太重?

而是:

你有没有在架构层,提前为复杂度准备"刹车系统"。

如果没有,再好的状态管理方案,最后都会变成负担。

相关推荐
数说星榆1812 小时前
在线简单画泳道图工具 PC端无水印
大数据·论文阅读·人工智能·架构·流程图·论文笔记
小雨下雨的雨2 小时前
Flutter跨平台开发实战: 鸿蒙与循环交互艺术:Sliver 视差滚动与沉浸式布局
flutter·华为·交互·harmonyos·鸿蒙系统
alonewolf_992 小时前
Tomcat整体架构深度解析:从设计精髓到实战应用
java·架构·tomcat
短剑重铸之日2 小时前
《7天学会Redis》Day 1 - Redis核心架构与线程模型
java·redis·后端·架构·i/o多路复用·7天学会redis
kirk_wang2 小时前
Flutter audioplayers 库鸿蒙平台适配实战:从原理到优化
flutter·移动开发·跨平台·arkts·鸿蒙
初恋叫萱萱2 小时前
技术基石与职场进阶:构建从Web后端到高性能架构的完整知识图谱
前端·架构·知识图谱
lpfasd1232 小时前
Nacos 实战指南:构建安全、高可用的微服务注册与配置中心
安全·微服务·架构
小雨下雨的雨2 小时前
Flutter跨平台开发实战: 鸿蒙与循环交互艺术:卡片堆叠与叠放切换动效
flutter·华为·交互·harmonyos·鸿蒙系统
小雨下雨的雨2 小时前
Flutter跨平台开发实战: 鸿蒙与循环交互艺术:分布式联动与多端状态同步
分布式·flutter·华为·交互·harmonyos·鸿蒙系统