打不垮的购物车:BlocSignal 搭配快速不可变集合打造稳健 Flutter 应用
来源:dev.to — 2026-09-06
📋 概述
作者从 Flutter 里「最危险的一行代码」讲起:state.items.add(newItem) 在原处改了一个列表实例,BlocSignal 做同步去重的 if(stateValue==newState) return 判断会发现新旧指向同一内存地址、认为没变化而丢弃这次 emit,于是 UI 完全不刷新——直到你无意点了别的输入框触发祖先重建,商品才猛然出现。标准 Dart 集合按内存指针而非内容比较相等、且默认可变,用在响应式状态容器里会引爆四种经典 bug:幽灵重建、被污染的撤销栈、防御性拷贝税、并发修改崩溃。
🔑 核心要点
- BlocSignal 的核心是把状态去重做成同步同帧机制:emit 时立刻 if(stateValue==newState) return——这正是它跑出 120 FPS 的秘密,但也与按指针比较的 Dart 集合正面相撞
- 四大集合状态 bug:幽灵重建(原地 add 后 identical 相等、emit 被丢、UI 冻结)、被污染的撤销栈(历史缓冲指向同一可变列表、改现在悄悄毁过去)、防御性拷贝税([...items,x] 每次按键拷贝上千引用撑爆 GC)、并发修改崩溃
- 解决方案是把 BlocSignal 与 fast_immutable_collections 配对:真正的值相等让 [1,2]==[1,2] 开箱即真、编译期不可变让原地修改根本过不了编译、持久结构共享提供 O(1)/O(logN) 的 copy-on-write 零 GC 压力
- 状态类可用单行 Dart 3 record 语法定义——不用跑 build_runner 的 freezed、不用写 30 行 Equatable 样板,去重与重建都被正确触发
- 作者的立足点不是「演示级正确」而是消除一整类客户端 bug 的架构纪律:让坏代码在编译期就失败,而非留到运行时让用户看见冻结的购物车
💡 金句
标准的 Dart 集合在响应式架构里是沉默的定时炸弹——它们按内存指针而非内容比较、能被应用任意一层就地修改,而你一旦用防御性展开拷贝去自保,就会在每个按键上付出残酷的复制税。
👍 0
👎 0
← 返回 dev.to 首页