

子玥酱 (掘金 / 知乎 / CSDN / 简书 同名)
大家好,我是 子玥酱,一名长期深耕在一线的前端程序媛 👩💻。曾就职于多家知名互联网大厂,目前在某国企负责前端软件研发相关工作,主要聚焦于业务型系统的工程化建设与长期维护。
我持续输出和沉淀前端领域的实战经验,日常关注并分享的技术方向包括 前端工程化、小程序、React / RN、Flutter、跨端方案,
在复杂业务落地、组件抽象、性能优化以及多端协作方面积累了大量真实项目经验。
技术方向: 前端 / 跨端 / 小程序 / 移动端工程化 内容平台: 掘金、知乎、CSDN、简书 创作特点: 实战导向、源码拆解、少空谈多落地 **文章状态:**长期稳定更新,大量原创输出
我的内容主要围绕 前端技术实战、真实业务踩坑总结、框架与方案选型思考、行业趋势解读 展开。文章不会停留在"API 怎么用",而是更关注为什么这么设计、在什么场景下容易踩坑、真实项目中如何取舍,希望能帮你在实际工作中少走弯路。
子玥酱 · 前端成长记录官 ✨
👋 如果你正在做前端,或准备长期走前端这条路
📚 关注我,第一时间获取前端行业趋势与实践总结
🎁 可领取 11 类前端进阶学习资源 (工程化 / 框架 / 跨端 / 面试 / 架构)
💡 一起把技术学"明白",也用"到位"
持续写作,持续进阶。
愿我们都能在代码和生活里,走得更稳一点 🌱
文章目录
-
- 引言
- [明确 Flutter 的性能责任在谁身上](#明确 Flutter 的性能责任在谁身上)
- [把"build 是什么"写进团队共识](#把“build 是什么”写进团队共识)
- 状态设计先于状态管理框架
- 列表是项目性能的第一等公民
-
- 列表的三条底线设计
-
- 一、列表项必须是"输入可控的纯组件"
- [二、列表外禁止 setState](#二、列表外禁止 setState)
- [三、key 是协议,不是装饰](#三、key 是协议,不是装饰)
- [把 rebuild 边界画出来](#把 rebuild 边界画出来)
- [Sliver 不是高级玩法,是基础设施](#Sliver 不是高级玩法,是基础设施)
- [Debug 卡不是"可以忽略的"](#Debug 卡不是“可以忽略的”)
- 性能规范必须文档化
- 总结
引言
如果你已经踩过一次大型 Flutter 项目的性能坑,再回头看,会发现一个残酷事实:
大多数性能问题,在项目第一个月就已经注定了。
不是因为你写错了某一行代码,而是一开始就没定义清楚哪些东西是"允许变的",哪些是不允许的。
一个 Flutter 大型项目,从一开始,性能应该怎么被设计出来。
明确 Flutter 的性能责任在谁身上
在 Flutter 里,框架不会替你兜住这些事情:
- rebuild 范围
- 状态粒度
- 列表生命周期
- 对象创建频率
这意味着:
- 你必须在设计阶段就回答这些问题
- 而不是等卡了再去分析
如果团队里没人对这些有明确共识,项目迟早会走向"靠感觉优化"。
把"build 是什么"写进团队共识
很多 Flutter 项目失控,源头只有一个:
把 build 当成了业务执行函数。
在大型项目里,build 必须被当成纯描述层。
一条硬性规则
-
build 里只允许:
- 取已经准备好的数据
- 组合 Widget
-
build 里禁止:
- 创建复杂对象
- 计算列表结构
- 触发副作用
dart
// 正确心智
Widget build(BuildContext context) {
return ItemView(
title: state.title,
selected: state.selected,
);
}
而不是:
dart
Widget build(BuildContext context) {
final items = computeItemsFromState(state);
return ListView(children: items);
}
这不是洁癖,是性能边界。
状态设计先于状态管理框架
选 Provider、Riverpod 还是 Bloc,并不会决定你的性能上限。
状态长什么样,才会。
一个长期安全的状态分层
-
页面状态(Page State)
- 是否 loading
- 当前 tab
-
列表状态(List State)
- items
- 分页信息
-
行为状态(Action State)
- 提交中
- 校验错误
这三类状态:
- 生命周期不同
- 更新频率不同
- rebuild 范围必须不同
绝对不要让一个 Provider 同时承载三种状态。
列表是项目性能的第一等公民
在大型项目里:
80% 的性能问题,最终都会体现在列表上。
列表的三条底线设计
一、列表项必须是"输入可控的纯组件"
dart
class ItemView extends StatelessWidget {
final ItemModel model;
const ItemView(this.model);
@override
Widget build(BuildContext context) {
return Text(model.title);
}
}
- 不读外部 Provider
- 不依赖全局状态
- 输入变,才重建
二、列表外禁止 setState
dart
// 错误
setState(() {
items[index].selected = true;
});
列表外层的任何 setState,都可能导致整表 rebuild。
三、key 是协议,不是装饰
- key 必须稳定
- key 必须来自业务唯一标识
- 不允许 index 充当 key
这是长期维护的生命线。
把 rebuild 边界画出来
在大型项目中,rebuild 边界必须是"可读的"。
推荐的结构习惯
- 页面 Widget:不订阅状态
- 子区域 Widget:只订阅自己关心的状态
- 列表项 Widget:不订阅任何状态
dart
Widget build(BuildContext context) {
return Column(
children: const [
HeaderView(),
Expanded(child: ListSection()),
],
);
}
dart
class ListSection extends StatelessWidget {
@override
Widget build(BuildContext context) {
final items = context.select((ListState s) => s.items);
return ListView.builder(
itemBuilder: (_, i) => ItemView(items[i]),
);
}
}
这不是代码风格,是性能契约。
Sliver 不是高级玩法,是基础设施
很多项目"后期才上 Sliver",本身就是一个信号:
- 列表结构一开始就没设计清楚
Sliver 的价值不在炫技,而在:
- 限定 rebuild 范围
- 限定布局影响面
- 把滚动结构变成声明式组合
在复杂页面中:
- 多列表
- 吸顶
- 可展开区域
Sliver 应该是默认方案,而不是优化手段。
Debug 卡不是"可以忽略的"
很多项目早期忽略了一个信号:
Debug 滑动很卡,但 Release 还行。
这是 Flutter 在提醒你:
- build 太重
- 布局太深
- 重建太频繁
Debug 卡,是结构问题;Release 卡,是事故。
性能规范必须文档化
如果你不把性能设计写下来,它就一定会被破坏。
大型 Flutter 项目里,至少应该有:
- build 使用规范
- Provider / State 作用域说明
- 列表开发约定
- rebuild 检查清单
性能不是靠"大家都懂",而是靠明确写出来的边界。
总结
Flutter 并不是一个"写错就会炸"的框架。
相反,它的问题在于:
- 你可以长期写"差一点"的代码
- 性能会一点点退化
- 直到某天无法收拾
一个健康的大型 Flutter 项目,性能不是靠优化堆出来的,而是:
- 结构限制出来的
- 边界设计出来的
- 团队共识维护出来的