Flutter重构ConnectionState相关switch case实现代码复用
Flutter FutureBuilder 状态逻辑复用重构方案
核心思路很简单:把所有场景通用的连接状态判断、加载/空态/无连接/报错的兜底UI逻辑抽成带泛型的公共组件,只把「拿到有效数据后渲染业务UI」的差异部分作为回调参数暴露出去,后续任何页面要用FutureBuilder,直接传对应异步请求和数据渲染逻辑就行,不用重复写大段switch分支。
第一步:封装通用泛型组件
直接写一个支持任意数据类型的GenericFutureBuilder,公共逻辑全内置,支持自定义不同状态下的占位组件:
import 'package:flutter/material.dart'; class GenericFutureBuilder<T> extends StatelessWidget { const GenericFutureBuilder({ super.key, required this.future, required this.dataBuilder, this.loadingWidget, this.noneWidget, this.emptyWidget, this.errorWidget, }); /// 要监听的异步请求 final Future<T>? future; /// 拿到有效非空数据后的渲染逻辑,由业务页面传入 final Widget Function(BuildContext context, T validData) dataBuilder; /// 以下为可选自定义状态组件,不传则使用默认样式 final Widget? loadingWidget; final Widget? noneWidget; final Widget? emptyWidget; final Widget? errorWidget; @override Widget build(BuildContext context) { return FutureBuilder<T>( future: future, builder: (context, snapshot) { switch (snapshot.connectionState) { case ConnectionState.none: return noneWidget ?? const Text("当前无网络连接"); case ConnectionState.active: case ConnectionState.waiting: return loadingWidget ?? const Center(child: CircularProgressIndicator()); case ConnectionState.done: // 补全原代码缺失的错误处理 if (snapshot.hasError) { return errorWidget ?? Center( child: Text("加载失败:${snapshot.error?.toString() ?? '未知错误'}"), ); } if (snapshot.hasData) { final data = snapshot.data; // 自动处理列表类型的空数据场景 if (data is List && data.isEmpty) { return emptyWidget ?? const Center(child: Text("暂无有效数据")); } // 数据校验通过,交给业务层渲染对应UI return dataBuilder(context, data as T); } // 无数据兜底 return emptyWidget ?? const Center(child: Text("暂无有效数据")); } }, ); } }
第二步:业务页面替换原有代码
原来写大段switch的地方直接用封装好的组件,只需要关心拿到数据之后怎么渲染,不用重复写状态判断:
// 商品列表示例 GenericFutureBuilder<List<ProductsList>>( future: _fetchProductsList, // 这里只写商品列表的渲染逻辑即可 dataBuilder: (context, productList) { return ListView.builder( primary: false, shrinkWrap: true, scrollDirection: Axis.horizontal, itemCount: productList.length, itemBuilder: (BuildContext context,int index){ return ProductCard( img: productList[index].image, title: productList[index].title, price: productList[index].price, rating: productList[index].rating.rate, discount: 50, onTap: () {} ); } ); }, )
灵活扩展说明
- 任意类型的异步数据都能复用:不管是返回用户信息、配置项这类单对象,还是订单列表、评论列表这类数组,只要指定对应泛型,传入future和渲染逻辑即可
- 支持单页面自定义状态样式:如果某个页面需要定制加载动画、空态文案、报错提示,直接给组件传对应的可选参数就行,不会影响其他页面的默认样式,比如:
GenericFutureBuilder<UserInfo>( future: _fetchUserInfo, // 自定义加载动画 loadingWidget: const Center(child: CircularProgressIndicator(color: Colors.blue, strokeWidth: 2,)), // 自定义空态 emptyWidget: const Center(child: Text("用户信息不存在")), dataBuilder: (context, userInfo) => UserProfileCard(user: userInfo), )
注:原代码存在一个逻辑疏漏,没有处理异步请求报错的场景,封装时补全了这部分逻辑,避免请求出错后页面一直卡在加载状态。
内容的提问来源于stack exchange,提问作者user10033434
相关产品推荐
相关产品推荐

