为何切换BottomNavigationBar时FutureBuilder会重复构建?
你遇到的核心问题是:切换底部导航栏时,HomeView的State会被销毁,切回页面时State重新创建,导致initState再次执行,_futureSerieA被重新初始化,最终触发FutureBuilder重复构建。
下面是两种可行的解决方法:
方法一:使用AutomaticKeepAliveClientMixin保持页面状态
让HomeView的State混入AutomaticKeepAliveClientMixin,页面切换时不会销毁State,initState只会执行一次:
class _HomeViewState extends State<HomeView> with AutomaticKeepAliveClientMixin { late final Future<List<DocumentSnapshot<Object?>>> _futureSerieA; @override void initState() { super.initState(); _futureSerieA = getScheduled("Serie A"); } // 重写该方法,返回true表示保持状态 @override bool get wantKeepAlive => true; @override Widget build(BuildContext context) { // 必须调用super.build,否则状态保持不生效 super.build(context); return SizedBox.expand( child: SingleChildScrollView( child: Column( children: [ // ... 你的原有代码 FutureBuilder( future: _futureSerieA, builder: (context, AsyncSnapshot<List<DocumentSnapshot>> snapshot) { // ... 原有builder逻辑 }, ) ], ), ), ); } }
方法二:将Future的初始化提升到父组件
把_futureSerieA的初始化放在父组件LoggedHandle中,通过构造函数传递给HomeView,避免页面切换时重新创建Future:
1. 修改HomeView,添加接收Future的构造函数
class HomeView extends StatefulWidget { final Future<List<DocumentSnapshot<Object?>>> futureSerieA; const HomeView({Key? key, required this.futureSerieA}) : super(key: key); @override _HomeViewState createState() => _HomeViewState(); } class _HomeViewState extends State<HomeView> { @override Widget build(BuildContext context) { return SizedBox.expand( child: SingleChildScrollView( child: Column( children: [ // ... 原有代码 FutureBuilder( future: widget.futureSerieA, builder: (context, AsyncSnapshot<List<DocumentSnapshot>> snapshot) { // ... 原有builder逻辑 }, ) ], ), ), ); } }
2. 在父组件LoggedHandle中初始化Future并传递
class _LoggedHandleState extends State<LoggedHandle> { double height = AppBar().preferredSize.height; int _selectedPage = 1; late final Future<List<DocumentSnapshot<Object?>>> _futureSerieA; late final List<Widget> _pageOptions; @override void initState() { super.initState(); _futureSerieA = getScheduled("Serie A"); // 初始化页面列表,传递Future给HomeView _pageOptions = [ const BetView(), HomeView(futureSerieA: _futureSerieA), const UserView() ]; } @override Widget build(BuildContext context) { return Scaffold( // ... 原有AppBar等代码 bottomNavigationBar: BottomNavigationBar( unselectedItemColor: Colors.white60, backgroundColor: Colors.red, selectedItemColor: Colors.white, currentIndex: _selectedPage, onTap: (int index) { setState(() { _selectedPage = index; }); }, items: const <BottomNavigationBarItem>[ BottomNavigationBarItem( icon: Icon(Icons.receipt), label: 'Schedina', ), BottomNavigationBarItem( icon: Icon(Icons.home), label: 'Home', ), BottomNavigationBarItem( icon: Icon(Icons.account_circle), label: 'Account', ), ], ), body: _pageOptions[_selectedPage], ); } }
两种方法对比:
- 方法一更适合单个页面需要保持状态的场景,实现简单。
- 方法二更适合多个页面需要共享同一个Future结果的场景,或者需要统一管理异步任务的场景。
内容的提问来源于stack exchange,提问作者faccio
相关产品推荐
相关产品推荐

