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

Flutter中initState调用JSON接口并跨组件传值失败求助

解决Flutter中initState调用接口后数据无法传递给子Widget的问题

我帮你排查了代码里的问题,主要有几个点导致数据没法正常加载并传递给CurrencyCard:

问题分析

  1. 变量作用域错误:你在setState里用var stgBuy = ...重新声明了变量,这会覆盖全局的同名变量,导致全局变量根本没被赋值,子Widget自然拿不到数据。
  2. 异步数据未处理加载状态:initState里的接口请求是异步的,build方法会先执行,这时候数据还没返回,子Widget使用的变量都是null,会引发错误。
  3. 全局变量不规范:用全局变量管理状态容易导致状态混乱,更好的做法是把数据放在State类内部。

修正方案

下面是修改后的完整代码,我会标注关键修改点:

/* My Json Data
{ "date":"20180515",
 "currency":{
 "dollar":{ "buy":"4,3600", "sell":"4,4600", },
 "sterling":{ "buy":"5,9350", "sell":"6,0350", },
 "euro":{ "buy":"5,2150", "sell":"5,3150", }
 }
}
*/
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;

final Color darkMainGreen = const Color(0xFF689F38);
final Color midMainGreen = const Color(0xFF7CB342);
final Color lightMainGreen = const Color(0xFF8BC34A);

// TODO: 1) MAIN
void main() {
 runApp(new MyApp());
}

// TODO: 2) MyApp
class MyApp extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return new MaterialApp(
 debugShowCheckedModeBanner: false,
 title: "MyDepo",
 home: new MyHomePage(title: "MyDepo"),
 );
 }
}

// TODO: 3) Statefull MyHomePage Class
class MyHomePage extends StatefulWidget {
 MyHomePage({Key key, this.title}) : super(key: key);

 final String title;

 @override
 _MyHomePageState createState() => new _MyHomePageState();
}

// TODO: 4) _MyHomePageState Class
class _MyHomePageState extends State<MyHomePage> {
 // --- 关键修改1:把数据变量移到State类内部,替换全局变量 ---
 Map<String, dynamic> currencyData;
 String stgBuy;
 String stgSell;
 String eurBuy;
 String eurSell;
 String usdBuy;
 String usdSell;

 // JSON: GET CURRENCY
 Future<String> getCurrencyJsonData() async {
 var response = await http.get(
 Uri.encodeFull("******* myJsonData *********"),
 headers: {'Accept': 'application/json'});

 setState(() {
 currencyData = json.decode(response.body);
 // --- 关键修改2:去掉var,直接给类内变量赋值 ---
 stgBuy = currencyData["currency"]["sterling"]["buy"];
 stgSell = currencyData["currency"]["sterling"]["sell"];
 eurBuy = currencyData["currency"]["euro"]["buy"];
 eurSell = currencyData["currency"]["euro"]["sell"];
 usdBuy = currencyData["currency"]["dollar"]["buy"];
 usdSell = currencyData["currency"]["dollar"]["sell"];
 });

 return "Success!";
 }

 // TODO: BUILD WIDGET
 @override
 Widget build(BuildContext context) {
 return new Scaffold(
 appBar: new AppBar(
 title: new Text(
 "MyDepo",
 style: TextStyle(fontSize: 18.0, fontWeight: FontWeight.w500),
 ),
 backgroundColor: midMainGreen,
 ),
 // --- 关键修改3:用FutureBuilder处理异步数据加载 ---
 body: FutureBuilder(
 future: getCurrencyJsonData(),
 builder: (context, snapshot) {
 // 数据加载中
 if (snapshot.connectionState == ConnectionState.waiting) {
 return Center(child: CircularProgressIndicator());
 }
 // 数据加载出错
 else if (snapshot.hasError) {
 return Center(child: Text("加载失败: ${snapshot.error}"));
 }
 // 数据加载完成
 else {
 return new ListView(
 padding: const EdgeInsets.all(0.0),
 children: <Widget>[
 new Padding(padding: EdgeInsets.fromLTRB(3.0, 4.0, 3.0, 4.0)),
 // --- 关键修改4:把数据传递给CurrencyCard ---
 CurrencyCard(
 stgBuy: stgBuy,
 stgSell: stgSell,
 eurBuy: eurBuy,
 eurSell: eurSell,
 usdBuy: usdBuy,
 usdSell: usdSell,
 ),
 ],
 );
 }
 },
 ),
 );
 }
}

// --- 关键修改5:修改CurrencyCard为接收参数的Widget ---
class CurrencyCard extends StatelessWidget {
 final String stgBuy;
 final String stgSell;
 final String eurBuy;
 final String eurSell;
 final String usdBuy;
 final String usdSell;

 CurrencyCard({
 required this.stgBuy,
 required this.stgSell,
 required this.eurBuy,
 required this.eurSell,
 required this.usdBuy,
 required this.usdSell,
 });

 @override
 Widget build(BuildContext context) {
 final redGradient = const LinearGradient(
 colors: const <Color>[const Color(0xFFBA110E), const Color(0xFFCF3110)],
 stops: const <double>[0.4, 0.6],
 begin: Alignment.topRight,
 end: Alignment.bottomLeft);

 final blueGraient = const LinearGradient(
 colors: const <Color>[const Color(0xFF0075D1), const Color(0xFF00A2E3)],
 stops: const <double>[0.5, 0.7],
 begin: Alignment.topLeft,
 end: Alignment.bottomRight);

 final greenGradient = const LinearGradient(colors: const <Color>[
 const Color(0xFF7CB342),
 const Color(0xFF8BC34A),
 ], stops: const <double>[
 0.6,
 0.8
 ], begin: Alignment.bottomRight, end: Alignment.topLeft);

 return new Container(
 constraints: const BoxConstraints(maxHeight: 90.0),
 margin: const EdgeInsets.all(10.0),
 child: new Align(
 alignment: Alignment.center,
 child: new ListView(
 shrinkWrap: true,
 scrollDirection: Axis.horizontal,
 children: <Widget>[
 _buildAction(
 "£ Sterling", "Buy: ", stgBuy, "Sell: ", stgSell, Colors.red, redGradient, AssetImage("assets/images/dollar.png")),
 _buildAction(
 "€ Euro", "Buy: ", eurBuy, "Sell: ", eurSell, Colors.blue, blueGraient, AssetImage("assets/images/euro.png")),
 _buildAction(
 "\$ Dollar", "Buy: ", usdBuy, "Sell: ", usdSell, Colors.green, greenGradient, AssetImage("assets/images/sterling.png")),
 ]),
 ),
 );
 }

 Widget _buildAction(
 String title, String titleAlis, String titleAlisValue, String titleSatis, String titleSatisValue, Color color, Gradient gradient, ImageProvider backgroundImage) {
 return new GestureDetector(
 child: new Container(
 margin: const EdgeInsets.only(right: 5.0, left: 5.0),
 width: 150.0,
 decoration: new BoxDecoration(
 color: color,
 shape: BoxShape.rectangle,
 borderRadius: new BorderRadius.circular(10.0),
 boxShadow: <BoxShadow>[
 new BoxShadow(
 color: Colors.black38,
 blurRadius: 2.0,
 spreadRadius: 1.0,
 offset: new Offset(0.0, 1.0)),
 ],
 gradient: gradient
 ),
 // --- 补充:把文本内容添加到卡片里,不然看不到数据 ---
 child: Padding(
 padding: EdgeInsets.all(8.0),
 child: Column(
 mainAxisAlignment: MainAxisAlignment.center,
 crossAxisAlignment: CrossAxisAlignment.start,
 children: [
 Text(title, style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold)),
 SizedBox(height: 4.0),
 Text("$titleAlis $titleAlisValue", style: TextStyle(color: Colors.white)),
 Text("$titleSatis $titleSatisValue", style: TextStyle(color: Colors.white)),
 ],
 ),
 ),
 ),
 );
 }
}

修改说明

  1. 变量作用域修正:把原来的全局变量移到_MyHomePageState类内部,并且在setState里直接赋值,不再用var重新声明。
  2. FutureBuilder处理异步:用FutureBuilder包裹页面内容,这样可以在数据加载时显示加载指示器,加载完成后再渲染包含数据的子Widget,确保build时数据已经准备好。
  3. 子Widget接收参数:修改CurrencyCard为接收参数的Widget,通过构造函数把数据传递进去,避免依赖全局变量,状态管理更清晰。
  4. 补充卡片内容:原来的_buildAction里没有添加文本内容,我补充了这部分,这样数据能显示在卡片上。

这样修改后,就能确保接口数据加载完成后再渲染子Widget,并且数据能正确传递和显示了。

内容的提问来源于stack exchange,提问作者user9239214

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 10:07:46