Flutter Bloc中无需存储状态监听操作触发子组件重建的方法
问题描述
我正在学习Flutter的Bloc状态管理库,遇到这样一个场景:希望监听某个操作(比如按钮点击),通过Cubit让组件树中的子组件对该操作做出响应。根据文档,重建子组件的唯一方式似乎是存储状态对象并响应状态变化,但我的场景无需存储任何状态,仅需知晓操作已执行,并在每次操作触发时做出响应。
如下方示例所示,我希望每次点击WidgetA中的按钮时,WidgetB都会重建,但不清楚如何在不存储状态对象的情况下构建对应的Cubit。
import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; // 如果不想存储任何状态,此处代码应如何编写? class WidgetACubit extends Cubit<void> { WidgetACubit({initialState}) : super(initialState); void doSomething() => emit(null); } class App extends StatelessWidget { App({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: BlocProvider( create: (_) => WidgetACubit(), child: WidgetA(), ), ), ); } } class WidgetA extends StatelessWidget { WidgetA({super.key}); @override Widget build(BuildContext context) { return Column( children: [ ElevatedButton( onPressed: () { BlocProvider.of<WidgetACubit>(context).doSomething(); print("Something has been done"); WidgetB.count++; }, child: const Text("Press me to do something"), ), WidgetB(), ], ); } } class WidgetB extends StatelessWidget { static int count = 0; WidgetB({super.key}); @override Widget build(BuildContext context) { return BlocBuilder<WidgetACubit, void>( builder: (context, state) { return Text("I've been rebuilt $count times"); }, ); } }
解决方案
你的核心问题在于:Bloc/Cubit只有在emit的状态与之前的状态不相等时,才会通知监听者触发重建。原代码中每次emit(null),由于null是同一个对象,Cubit会认为状态没有变化,因此不会触发WidgetB的重建。
针对“无需存储状态,仅需触发操作响应”的场景,有两种简单的实现方式:
方式1:使用空状态类
定义一个专门的空状态类,每次操作时emit该类的新实例,确保每次状态都是不同的对象:
class WidgetACubit extends Cubit<ActionPerformed> { WidgetACubit() : super(ActionPerformed()); void doSomething() => emit(ActionPerformed()); } // 空状态类,仅用于标记操作已执行 class ActionPerformed {}
对应的WidgetB需要更新泛型参数:
class WidgetB extends StatelessWidget { static int count = 0; WidgetB({super.key}); @override Widget build(BuildContext context) { return BlocBuilder<WidgetACubit, ActionPerformed>( builder: (context, state) { return Text("I've been rebuilt $count times"); }, ); } }
方式2:emit新的匿名对象
如果不想额外定义状态类,可以每次emit一个新的Object()实例,因为每次创建的Object都是不同的引用:
class WidgetACubit extends Cubit<Object> { WidgetACubit() : super(Object()); void doSomething() => emit(Object()); }
对应的WidgetB泛型参数改为Object:
class WidgetB extends StatelessWidget { static int count = 0; WidgetB({super.key}); @override Widget build(BuildContext context) { return BlocBuilder<WidgetACubit, Object>( builder: (context, state) { return Text("I've been rebuilt $count times"); }, ); } }
额外优化:避免静态变量计数
原代码中用static int count的方式并不符合Flutter的状态管理规范,建议将计数逻辑移到Cubit中(即使你认为不需要存储状态,其实计数本身就是一种状态),这样更符合Bloc的设计思想:
class WidgetACubit extends Cubit<int> { WidgetACubit() : super(0); void doSomething() => emit(state + 1); } // WidgetB的实现 class WidgetB extends StatelessWidget { WidgetB({super.key}); @override Widget build(BuildContext context) { return BlocBuilder<WidgetACubit, int>( builder: (context, count) { return Text("I've been rebuilt $count times"); }, ); } } // WidgetA的按钮点击逻辑 ElevatedButton( onPressed: () { BlocProvider.of<WidgetACubit>(context).doSomething(); print("Something has been done"); }, child: const Text("Press me to do something"), )
这样既满足了每次点击触发重建的需求,又遵循了状态管理的最佳实践,避免了静态变量带来的潜在问题。
内容的提问来源于stack exchange,提问作者Flik
相关产品推荐
相关产品推荐

