You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bloc 7.2.0版本中BlocSelector的使用方法及实际应用示例咨询

Bloc 7.2.0 版本 BlocSelector 组件使用说明

BlocSelector 是Bloc库提供的状态监听组件,核心作用是只监听Bloc/Cubit全量状态中的指定局部字段,仅当目标字段发生变化时才触发组件重绘,相比全量监听状态的BlocBuilder可以大幅减少不必要的渲染,提升页面性能。

基础参数说明

  • 泛型参数从左到右依次为:目标Bloc/Cubit的类型、Bloc对应的全量状态类型、你筛选出的局部状态的类型
  • selector 参数:接收全量状态作为入参,返回你需要监听的局部状态
  • builder 参数:接收上下文和筛选出的局部状态作为入参,返回对应渲染的Widget

实际使用示例

我们以用户信息管理场景为例,先定义对应的Cubit和状态类:

import 'package:bloc/bloc.dart';
import 'package:flutter/foundation.dart';

// 用户状态类
class UserState {
  final String username;
  final String avatarUrl;
  final String phone;

  const UserState({
    required this.username,
    required this.avatarUrl,
    required this.phone,
  });

  // 状态更新用copyWith
  UserState copyWith({
    String? username,
    String? avatarUrl,
    String? phone,
  }) {
    return UserState(
      username: username ?? this.username,
      avatarUrl: avatarUrl ?? this.avatarUrl,
      phone: phone ?? this.phone,
    );
  }

  // 重写==和hashCode保证状态变化可被检测
  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is UserState &&
          runtimeType == other.runtimeType &&
          username == other.username &&
          avatarUrl == other.avatarUrl &&
          phone == other.phone;

  @override
  int get hashCode => username.hashCode ^ avatarUrl.hashCode ^ phone.hashCode;
}

// 对应的Cubit
class UserCubit extends Cubit<UserState> {
  UserCubit() : super(const UserState(username: "游客", avatarUrl: "", phone: ""));

  // 更新用户名
  void updateUsername(String newName) {
    emit(state.copyWith(username: newName));
  }

  // 更新手机号
  void updatePhone(String newPhone) {
    emit(state.copyWith(phone: newPhone));
  }
}

单字段监听示例

以下代码仅监听username字段变化,当调用updatePhone更新手机号时,该组件不会触发重绘:

BlocSelector<UserCubit, UserState, String>(
  selector: (state) => state.username,
  builder: (context, username) {
    return Text(
      "欢迎您:$username",
      style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
    );
  },
)

多字段监听示例

如果需要同时监听多个字段,可以返回元组或者自定义的不可变对象:

// 同时监听用户名和头像两个字段
BlocSelector<UserCubit, UserState, (String, String)>(
  selector: (state) => (state.username, state.avatarUrl),
  builder: (context, userInfo) {
    return Row(
      children: [
        // 展示头像,avatarUrl为空时展示默认占位图
        userInfo.$2.isEmpty
            ? const Icon(Icons.account_circle, size: 40)
            : Image.network(userInfo.$2, width: 40, height: 40, fit: BoxFit.cover),
        const SizedBox(width: 12),
        Text(userInfo.$1),
      ],
    );
  },
)

注意事项

  • selector返回的状态必须是不可变的,如果返回自定义对象必须重写==和hashCode,也可以直接使用equatable库自动生成对比逻辑,否则无法正确检测状态变化
  • 不建议在selector中做复杂计算,该函数会在每次全量状态更新时执行,复杂计算会影响性能
  • 如果需要监听全量状态的变化,直接使用BlocBuilder即可,不需要用BlocSelector

内容的提问来源于stack exchange,提问作者Mariam Albarghouti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 13:45:04