You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何切换BottomNavigationBar时FutureBuilder会重复构建?

解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 17:27:26