我在颤振中使用 bloc 模式,我想知道构建代码的最佳方法是什么,以避免在我的 StreamBuilder 中进行不必要的重建
根据我到目前为止在颤动中学到的知识,bloc 模式中的 bloc 组件接受一个事件流并将它们映射到一个状态流,然后可以在 StreamBuilder 中使用该状态流来构建 UI。
按照这个范例,我创建了一个状态类,其中包括我的屏幕所需的所有状态属性
并且还创建了一个事件类,每个类都描述了可能发生的事件
我的 bloc 组件包含两个流控制器,一个监听事件,然后将它们相应地映射到状态,然后将它们添加到状态流
在屏幕小部件中,我有一个 StreamBuilder 包装了可能更新的小部件,并且此 StreamBuilder 将块状态流作为流
当用户与屏幕 UI 交互时,相应的事件将被触发并添加到 bloc 中的事件流中,并且循环继续进行。
然而,使用这种方法,我注意到 StreamBuilder 每次发生事件时都会在 build 方法中重建所有小部件,即使小部件不需要状态流中的 snapshot.data 实际上很少有小部件需要实际流数据,但所有小部件都将重建。
我对此进行了一些思考和研究,但没有给出明确的答案。我的意思是我正在遵循 bloc 模式的描述 bloc 组件如何接受事件并将其转换为状态
但是当状态模型包含许多属性时,StreamBuilder 中的小部件会有许多不必要的重建
但是在这种情况下,我想出了两个选择
选项 1:在 bloc 组件中,将 State 流分成多个流,每个流对应 State 的每个属性
-> 这种方法的问题:
是在屏幕 UI 中,每组使用相同属性的小部件将聚集在一起并用 StreamBuilder 包装,在这种情况下,我们会在 UI 中找到许多 StreamBuilder。
选项 2:在 StreamBuilder 内部以某种方式告诉小部件如果传递的参数与前一个参数没有变化,则不要重建,但直到现在我找不到解决方案如何实现这个
*不同的文件用虚线分隔
class ScreenBloc {
ScreenState _screenState = ScreenState.initial();
final _screenStateController = StreamController<ScreenState>();
StreamSink<ScreenState> get screenStateSink =>
_screenStateController.sink;
Stream<ScreenState> get screenStateStream =>
_screenStateController.stream;
final _screenEventController = StreamController<ScreenEvent>();
StreamSink<ScreenEvent> get screenEvenSink =>
_screenEventController.sink;
Function get dispatch => screenEvenSink.add;
ScreenBloc() {
ScreenStateSink.add(_screenState); //initial data for the stream
_screenEventController.stream.listen(_mapEventToState);
}
void _mapEventToState(ScreenEvent event) {
//map events to state then add them to the ScreenStateSink
}
}
------------------------------------------------------------------------
class ScreenState {
final propertyOne;
final propertyTwo;
final propertyThree;
ScreenState._({this.propertyOne,this.propertyTwo,this.propertyThree});
factory ScreenState.initial() {
// initalize
);
}
}
------------------------------------------------------------------------
abstract class ScreenEvent {}
class EventOne extends ScreenEvent {}
class EventTwo extends ScreenEvent {}
class EventThree extends ScreenEvent {}
------------------------------------------------------------------------
//Screen
final ScreenBloc _screenBloc = ScreenBloc();
Widget build(BuildContext context) {
return StreamBuilder<ScreenState>(
stream: _screenBloc.screenStateStream,
builder:
(BuildContext context, AsyncSnapshot<ScreenState> snapshot) {
return Column(
children: <Widget>[
WidgetOne(snapshot.data.property1),
WidgetTwo(snapshot.data.property2),
WidgetThree(snapshot.data.property3),
]
);
}
}