BlocBuilder的buildWhen与BlocSelector的核心差异及实际表现解析
BlocBuilder的buildWhen与BlocSelector的selector实际差异解析
核心差异拆解
1. 触发时机与执行频率
- buildWhen:仅在Bloc状态发生变更时执行。只有当Bloc发出新的状态对象时,才会调用buildWhen对比前后完整状态,返回
true才触发builder重建;如果Bloc状态没变化,哪怕父组件重建,buildWhen也不会执行,builder也不会触发。 - selector:在两个场景下都会执行:一是Bloc状态变更时,二是Widget自身触发build(比如父组件重建、自身依赖更新)时。每次执行都会从当前状态中提取目标值,只有当提取值与上一次结果不相等(默认用
==判断)时,才会触发builder重建。
2. 对比逻辑的维度
- buildWhen:对比的是完整的Bloc前后状态对象,你可以自定义任意复杂的判断逻辑。比如同时判断状态的多个字段变化、状态类型切换等。
- selector:对比的是你指定提取的子状态/值,逻辑聚焦在你关心的部分,不需要手动处理全量状态的对比。比如只提取状态中的用户名称、某个数值,只要这个值不变,就不会触发重建。
3. 性能优化的侧重点
- buildWhen:主要用来过滤Bloc端的无效状态更新。比如Bloc会频繁发送状态,但大部分状态变化和当前组件无关,用buildWhen直接跳过这些更新,避免进入builder逻辑。
- selector:主要用来屏蔽Widget端的无效重建触发。即使Widget因为父组件重建等原因触发build流程,只要selector提取的值没变化,就不会重复执行builder,减少不必要的渲染操作。
4. 适用场景区分
- 当你需要基于完整状态的复杂条件决定是否重建时,选buildWhen。比如:只有当状态从
Loading切换到Success,或者Error状态的错误码发生变化时才重建。 - 当你只关心状态中的某一个/几个特定字段,且希望在任何触发build的场景下都只在这些字段变化时才重建,选selector。比如:组件仅展示用户昵称,就用selector提取昵称字段,不管其他状态字段怎么变,只要昵称不变就不重建。
示例对比
假设Bloc状态为UserState(name: String, age: int):
使用buildWhen:
BlocBuilder<UserBloc, UserState>( buildWhen: (previous, current) => previous.name != current.name, builder: (context, state) => Text(state.name), )
只有Bloc状态变化且name字段不同时,才会触发builder;父组件重建时,若Bloc状态未变,builder不会执行。
使用selector:
BlocSelector<UserBloc, UserState, String>( selector: (state) => state.name, builder: (context, name) => Text(name), )
无论是Bloc状态变化导致name改变,还是父组件重建,selector都会执行;但只要name未变,builder就不会触发。
内容的提问来源于stack exchange,提问作者TpoM6oH
相关产品推荐
相关产品推荐

