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

Flutter底部导航栏页面无法传递数据问题求助

问题解决:ProScreen无法获取API加载后的coins值

问题场景

在home.dart主页中,通过底部导航栏管理多个页面,initState中初始化页面列表_pageOptions的同时,调用异步方法initializeCoins从API获取用户积分并更新Values.coins。AppBar能正常展示更新后的积分,但传递给ProScreen构造函数的始终是初始值0。

相关代码片段

初始化页面列表的代码:

late final List<Widget> _pageOptions;
@override
void initState() {
  appBarColor = colors[4];
  initializeCoins();
  _pageOptions = [
    ProScreen(Values.coins.toString()),
    CatScreen(),
    NotScreen(),
    FavScreen(),
    HomeScreen(),
  ];
  super.initState();
}

Values类定义:

class Values{
   static int coins = 0;
...
}

异步加载积分的方法:

Future<void> initializeCoins() async {
  _prefs =await  SharedPreferences.getInstance();
  var response = await http.get(Uri.parse(Values.url+Values.user_endpoint),
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ${_prefs?.getString('token')}',
      }
  );
  setState(() {
    coinsLoaded = true;
    Values.coins = (jsonDecode(response.body)['user']['score']);
  });
}

问题原因

initializeCoins是异步方法,initState调用它后会继续执行创建_pageOptions的代码,此时Values.coins还未被API请求更新,仍为初始值0。后续setState更新Values.coins时,_pageOptions中的ProScreen已用旧值完成初始化,不会自动刷新。

解决方案

方案1:在build方法中动态创建当前页面

不再提前初始化完整的_pageOptions列表,而是在build时根据当前选中的索引动态构建页面,确保每次setState后ProScreen都能获取最新的Values.coins值。

修改代码如下:

// 移除late final List<Widget> _pageOptions;定义

@override
void initState() {
  appBarColor = colors[4];
  initializeCoins();
  super.initState();
}

// 根据当前索引返回对应页面
Widget _getCurrentPage() {
  switch (_currentIndex) { // _currentIndex为底部导航栏当前选中索引
    case 0:
      return ProScreen(Values.coins.toString());
    case 1:
      return CatScreen();
    case 2:
      return NotScreen();
    case 3:
      return FavScreen();
    case 4:
      return HomeScreen();
    default:
      return HomeScreen();
  }
}

// 在build的Scaffold中使用该方法
@override
Widget build(BuildContext context) {
  return Scaffold(
    body: _getCurrentPage(),
    bottomNavigationBar: BottomNavigationBar(
      currentIndex: _currentIndex,
      onTap: (index) {
        setState(() {
          _currentIndex = index;
        });
      },
      // 其他底部导航栏配置
    ),
  );
}

方案2:异步请求完成后更新页面列表

若希望保留_pageOptions的方式,可在initializeCoins的setState中重新初始化_pageOptions,确保ProScreen使用最新的Values.coins。

修改代码如下:

late List<Widget> _pageOptions; // 去掉final,允许重新赋值

@override
void initState() {
  appBarColor = colors[4];
  initializeCoins();
  // 先初始化带默认值的页面列表
  _pageOptions = [
    ProScreen(Values.coins.toString()),
    CatScreen(),
    NotScreen(),
    FavScreen(),
    HomeScreen(),
  ];
  super.initState();
}

Future<void> initializeCoins() async {
  _prefs =await  SharedPreferences.getInstance();
  var response = await http.get(Uri.parse(Values.url+Values.user_endpoint),
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ${_prefs?.getString('token')}',
      }
  );
  setState(() {
    coinsLoaded = true;
    Values.coins = (jsonDecode(response.body)['user']['score']);
    // 更新页面列表,传递最新coins值
    _pageOptions = [
      ProScreen(Values.coins.toString()),
      CatScreen(),
      NotScreen(),
      FavScreen(),
      HomeScreen(),
    ];
  });
}

方案3:用状态管理让ProScreen自动监听值变化

若不想频繁重建页面,可使用ValueNotifier管理coins值,让ProScreen监听值的变化,仅更新需要展示的部分。

首先修改Values类:

class Values{
   static final ValueNotifier<int> coins = ValueNotifier(0);
...
}

然后修改initializeCoins方法:

Future<void> initializeCoins() async {
  _prefs =await  SharedPreferences.getInstance();
  var response = await http.get(Uri.parse(Values.url+Values.user_endpoint),
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ${_prefs?.getString('token')}',
      }
  );
  // 直接更新ValueNotifier的值
  Values.coins.value = (jsonDecode(response.body)['user']['score']);
  // 若需刷新页面其他部分,再调用setState
  setState(() {
    coinsLoaded = true;
  });
}

最后修改ProScreen,使用ValueListenableBuilder监听值变化:

class ProScreen extends StatelessWidget {
  const ProScreen({Key? key}) : super(key: key); // 无需构造函数传值

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<int>(
      valueListenable: Values.coins,
      builder: (context, coinsValue, child) {
        // 使用coinsValue构建UI
        return Scaffold(
          body: Center(
            child: Text('Coins: $coinsValue'),
          ),
        );
      },
    );
  }
}

内容的提问来源于stack exchange,提问作者S.Beigi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 17:25:19