← Назад к вопросам

Как следить за изменниями компонента в BLoC?

2.0 Middle🔥 131 комментариев
#State Management

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как следить за изменениями компонента в BLoC

BLoC (Business Logic Component) — это паттерн управления состоянием в Flutter, который использует Streams и Events для отделения бизнес-логики от UI. Отслеживание изменений компонента — ключевая часть работы с BLoC.

Основные способы отслеживания изменений

1. BlocListener

BlocListener реагирует на изменения состояния и выполняет побочные эффекты (навигация, диалоги, снэки):

BlocListener<CounterBloc, CounterState>(
  listener: (context, state) {
    if (state is CounterError) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(state.error)),
      );
    }
  },
  child: BlocBuilder<CounterBloc, CounterState>(
    builder: (context, state) {
      return Text('Счёт: ${state.count}');
    },
  ),
)

2. BlocBuilder

BlocBuilder перестраивает UI при изменении состояния:

BlocBuilder<CounterBloc, CounterState>(
  builder: (context, state) {
    if (state is CounterLoading) {
      return CircularProgressIndicator();
    } else if (state is CounterLoaded) {
      return Text('Значение: ${state.count}');
    } else if (state is CounterError) {
      return Text('Ошибка: ${state.error}');
    }
    return SizedBox();
  },
)

3. BlocConsumer

BlocConsumer объединяет слушатель и построитель в одном виджете:

BlocConsumer<AuthBloc, AuthState>(
  listener: (context, state) {
    if (state is AuthSuccess) {
      Navigator.pushReplacementNamed(context, '/home');
    }
  },
  builder: (context, state) {
    if (state is AuthLoading) {
      return Center(child: CircularProgressIndicator());
    }
    return LoginForm();
  },
)

Селекторы состояния

ListenableSelector и BlocSelector позволяют слушать только определённые части состояния:

// Слушать только изменения имени пользователя
BlocSelector<UserBloc, UserState, String>(
  selector: (state) => state.userName,
  builder: (context, userName) {
    return Text('Привет, $userName');
  },
)

Расширенное отслеживание

Через stream.listen

@override
Widget build(BuildContext context) {
  return BlocListener<DataBloc, DataState>(
    listener: (context, state) {
      // Выполнить действие при изменении
      _handleStateChange(state);
    },
    child: Scaffold(
      appBar: AppBar(title: Text('Данные')),
      body: BlocBuilder<DataBloc, DataState>(
        builder: (context, state) {
          if (state is DataLoading) {
            return Center(child: CircularProgressIndicator());
          }
          if (state is DataLoaded) {
            return ListView.builder(
              itemCount: state.items.length,
              itemBuilder: (context, index) {
                return ListTile(title: Text(state.items[index]));
              },
            );
          }
          return SizedBox();
        },
      ),
    ),
  );
}

Кастомные слушатели

class CustomBlocListener<B extends BlocBase, S> extends BlocListener<B, S> {
  CustomBlocListener({
    required B bloc,
    required void Function(BuildContext, S) listener,
    required Widget child,
  }) : super(
    bloc: bloc,
    listener: listener,
    child: child,
  );
}

Управление подписками

class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  late StreamSubscription _subscription;

  @override
  void initState() {
    super.initState();
    final bloc = context.read<CounterBloc>();
    
    _subscription = bloc.stream.listen((state) {
      print('Новое состояние: $state');
      // Обновить UI вручную если нужно
    });
  }

  @override
  void dispose() {
    _subscription.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text('Отслеживание изменений'),
      ),
    );
  }
}

Лучшие практики

  • BlocListener для побочных эффектов (навигация, диалоги)
  • BlocBuilder для перестройки UI
  • BlocConsumer когда нужно оба
  • BlocSelector для оптимизации — слушать только нужные поля
  • Правильная иерархия — слушатели близко к листьям, стейт-менеджер вверху
  • Отписываться от потоков в dispose, если используешь stream.listen() вручную

Правильное использование этих методов позволяет создавать реактивные, производительные приложения с чистой архитектурой.

Как следить за изменниями компонента в BLoC? | PrepBro