Flutter开发中如何避免重复编写StreamBuilder代码?
三层StreamBuilder封装实现方案
失效原因
此前方案失效的核心原因是仅将子Widget作为静态参数传入封装组件,没有暴露三层Stream获取到的数据给子组件,无法完成数据传递。
实现思路
使用Widget构建器函数替代直接传入子Widget,将三层Stream返回的列表数据整合后作为参数传递给构建器,使用侧直接在构建器中接收数据生成业务UI即可。
封装代码
// 整合三层Stream返回的数据结构 class TripleStreamData<T1, T2, T3> { final List<T1>? firstList; final List<T2>? secondList; final List<T3>? thirdList; final bool isLoading; final Object? error; TripleStreamData({ this.firstList, this.secondList, this.thirdList, this.isLoading = true, this.error, }); } // 封装后的三层StreamBuilder通用组件 class TripleStreamBuilder<T1, T2, T3> extends StatelessWidget { final Stream<List<T1>> firstStream; final Stream<List<T2>> secondStream; final Stream<List<T3>> thirdStream; // 数据回调构建器,封装组件将数据通过该参数回传给使用侧 final Widget Function(BuildContext context, TripleStreamData<T1, T2, T3> data) builder; const TripleStreamBuilder({ super.key, required this.firstStream, required this.secondStream, required this.thirdStream, required this.builder, }); @override Widget build(BuildContext context) { return StreamBuilder<List<T1>>( stream: firstStream, builder: (context, firstSnapshot) { return StreamBuilder<List<T2>>( stream: secondStream, builder: (context, secondSnapshot) { return StreamBuilder<List<T3>>( stream: thirdStream, builder: (context, thirdSnapshot) { // 统一处理错误状态 if (firstSnapshot.hasError || secondSnapshot.hasError || thirdSnapshot.hasError) { return builder( context, TripleStreamData( error: firstSnapshot.error ?? secondSnapshot.error ?? thirdSnapshot.error, isLoading: false, ), ); } // 统一处理加载中状态 if (firstSnapshot.connectionState == ConnectionState.waiting || secondSnapshot.connectionState == ConnectionState.waiting || thirdSnapshot.connectionState == ConnectionState.waiting) { return builder(context, TripleStreamData(isLoading: true)); } // 所有数据加载完成后回传给使用侧 return builder( context, TripleStreamData( firstList: firstSnapshot.data, secondList: secondSnapshot.data, thirdList: thirdSnapshot.data, isLoading: false, ), ); }, ); }, ); }, ); } }
使用示例
TripleStreamBuilder<User, Order, Product>( firstStream: userListStream, // 替换为你的第一个列表Stream secondStream: orderListStream, // 替换为你的第二个列表Stream thirdStream: productListStream, // 替换为你的第三个列表Stream builder: (context, data) { if (data.isLoading) { return const Center(child: CircularProgressIndicator()); } if (data.error != null) { return Center(child: Text('加载出错:${data.error.toString()}')); } // 直接使用三个列表数据构建业务UI final userList = data.firstList!; final orderList = data.secondList!; final productList = data.thirdList!; return ListView( children: [ Text('用户总数:${userList.length}'), Text('订单总数:${orderList.length}'), Text('商品总数:${productList.length}'), // 其余业务UI代码 ], ); }, )
优化建议
- 若三个Stream无先后依赖关系,可使用
StreamZip合并三个Stream减少嵌套层级,提升代码可读性 - 可根据业务需求自定义加载、错误状态的默认UI,进一步减少重复代码
内容的提问来源于stack exchange,提问作者user3234809
相关产品推荐
相关产品推荐

