在这里插入图片描述
在这里插入图片描述

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

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

我持续输出和沉淀前端领域的实战经验,日常关注并分享的技术方向包括 前端工程化、小程序、React / RN、Flutter、跨端方案
在复杂业务落地、组件抽象、性能优化以及多端协作方面积累了大量真实项目经验。

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

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

子玥酱 · 前端成长记录官 ✨
👋 如果你正在做前端,或准备长期走前端这条路
📚 关注我,第一时间获取前端行业趋势与实践总结
🎁 可领取 11 类前端进阶学习资源(工程化 / 框架 / 跨端 / 面试 / 架构)
💡 一起把技术学“明白”,也用“到位”

持续写作,持续进阶。
愿我们都能在代码和生活里,走得更稳一点 🌱

大多数 Flutter 列表性能问题,不是“写错了”,而是写得太随意了

它们在 Demo 里没问题、在首版也没问题、在数据量小的时候更没问题,但一旦:

  • 页面常驻
  • 状态变复杂
  • 列表变长
  • 需求开始叠加

问题一定会出现。

这套“安全写法”要解决什么问题

我们先明确目标,不是为了“更快”,而是为了:

  • rebuild 范围可预测
  • 滚动成本稳定
  • 状态位置清晰
  • 后期改需求不崩盘

总结:

让列表的性能,和业务复杂度“线性增长”,而不是指数爆炸。

列表容器不承载业务状态

永远不要这样写

class ListPage extends StatelessWidget {
  
  Widget build(BuildContext context) {
    final model = context.watch<ListModel>();

    return ListView.builder(
      itemCount: model.items.length,
      itemBuilder: ...
    );
  }
}

问题不在 ListView,而在这句:

context.watch<ListModel>()

这等于在告诉 Flutter:

“整个列表,依赖整个业务模型。”

长期安全写法

class ListPage extends StatelessWidget {
  
  Widget build(BuildContext context) {
    final count = context.select<ListModel, int>(
      (m) => m.items.length,
    );

    return ListView.builder(
      itemCount: count,
      itemBuilder: (context, index) {
        return ItemTile(index: index);
      },
    );
  }
}

列表容器只关心结构,不关心内容。

item 是 rebuild 的最小战斗单位

Flutter 列表的“安全边界”,是 item,而不是列表。

Item 必须满足三点

  1. 足够小
  2. 足够纯
  3. 状态明确

推荐的 Item 写法

class ItemTile extends StatelessWidget {
  final int index;
  const ItemTile({required this.index});

  
  Widget build(BuildContext context) {
    final item = context.select<ListModel, Item>(
      (m) => m.items[index],
    );

    return ListTile(
      title: Text(item.title),
      subtitle: Text(item.subtitle),
    );
  }
}

rebuild 边界非常明确:

只有这个 item 的数据变了,它才 rebuild。

能 Stateless,就不要 Stateful

这是 Flutter 列表里一个长期收益极高的习惯

Stateful item 的隐性成本

  • 状态容易被 keepAlive
  • Element 复用时更复杂
  • 错位问题更隐蔽

很多“诡异 Bug”,都来自 Stateful item。

如果你真的需要局部状态

比如:

  • 是否展开
  • 是否选中
  • 动画进度

明确声明它的生命周期

class ExpandableItem extends StatefulWidget {
  final Item item;
  const ExpandableItem({required this.item});

  
  State<ExpandableItem> createState() => _ExpandableItemState();
}

class _ExpandableItemState extends State<ExpandableItem> {
  bool expanded = false;

  
  Widget build(BuildContext context) {
    return Column(
      children: [
        ListTile(
          title: Text(widget.item.title),
          onTap: () {
            setState(() => expanded = !expanded);
          },
        ),
        if (expanded) Text(widget.item.detail),
      ],
    );
  }
}

并且默认不 keepAlive

key 不是可选项

在长期维护的列表中:

没有 key 的列表,迟早出事。

正确使用 key

return ItemTile(
  key: ValueKey(item.id),
  index: index,
);

不要用:

  • index
  • hashCode
  • runtimeType

key 的本质是身份,而不是位置。

列表 item 里不做“异步决策”

危险写法

itemBuilder: (context, index) {
  return FutureBuilder(
    future: fetchExtra(items[index].id),
    builder: ...
  );
}

问题不是 FutureBuilder,而是:

  • 滚动时会频繁触发
  • build 不再是纯函数
  • Debug 下性能极差

长期安全替代方案

  • 异步逻辑提前到 model
  • item 只展示状态
class Item {
  final String title;
  final String? extra;
}

页面复杂了,优先 Sliver

当你出现以下需求时:

  • Header + 列表
  • 吸顶
  • 多段列表
  • 页面常驻

不要犹豫,直接 Sliver。

推荐结构模板

CustomScrollView(
  slivers: [
    SliverToBoxAdapter(
      child: HeaderView(),
    ),
    SliverList(
      delegate: SliverChildBuilderDelegate(
        (context, index) {
          return ItemTile(index: index);
        },
        childCount: count,
      ),
    ),
  ],
);

Sliver 的好处不是快,而是:

  • rebuild 传播路径短
  • 结构天然清晰
  • 后期加需求不翻车

keepAlive 是“高级权限”

AutomaticKeepAliveClientMixin
在列表里,永远是最后考虑的选项

问问自己三个问题

  1. 这个状态真的值得活着吗?
  2. 离开屏幕后还能复用吗?
  3. 内存上涨你能接受吗?

如果有一个答不上来:

不要 keepAlive。

“长期安全”的完整 Demo 结构

class ListModel extends ChangeNotifier {
  final List<Item> items = [];

  void updateItem(int index, Item newItem) {
    items[index] = newItem;
    notifyListeners();
  }
}
class ListPage extends StatelessWidget {
  
  Widget build(BuildContext context) {
    final count = context.select<ListModel, int>(
      (m) => m.items.length,
    );

    return CustomScrollView(
      slivers: [
        SliverToBoxAdapter(child: HeaderView()),
        SliverList(
          delegate: SliverChildBuilderDelegate(
            (context, index) {
              return ItemTile(
                key: ValueKey(
                  context.read<ListModel>().items[index].id,
                ),
                index: index,
              );
            },
            childCount: count,
          ),
        ),
      ],
    );
  }
}

长期“安全”的原因

总结一下它解决了什么:

  • rebuild 边界清晰
  • item 粒度稳定
  • 滚动成本可控
  • 状态不扩散
  • Debug / Release 行为一致

总结

Flutter 列表性能,从来不是靠“技巧堆出来的”。

真正能活得久的列表,只有一个特征:

结构清楚,状态克制。

当你把这套写法变成肌肉记忆之后:

  • Debug 下你会更安心
  • 需求改动你会更从容
  • 性能问题会变成“可以推理的问题”
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐