为什么我的 Flutter JSON 数据没有从 setState 更新?
Why my Flutter JSON data didn't updated from setState?
我制作了 JSON 数据并使用 ListView.builder 小部件将其显示在 FutureBuilder 中。我想在ListView.builder的尾部创建一个喜欢的Icon。所以我用 IconButton 创建了它,但是当我创建 setState 使某些项目成为收藏夹时,数据没有更新。
这是我的代码
import 'package:flutter/material.dart';
import 'package:json_test/class/doa.dart';
import 'package:json_test/page/DoaPage.dart';
class MainPage extends StatefulWidget {
@override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
Future<List<Doa>> fetchDoa(BuildContext context) async {
final jsonstring =
await DefaultAssetBundle.of(context).loadString('assets/doa.json');
return doaFromJson(jsonstring);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("JSON Data test"),
),
body: Container(
child: FutureBuilder(
future: fetchDoa(context),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
Doa doa = snapshot.data[index];
return Card(
margin: EdgeInsets.all(8),
child: ListTile(
title: Text(doa.judul),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) =>
DoaPage(
doa: doa,
)));
},
trailing: IconButton(
icon: Icon(
doa.fav
? Icons.favorite
: Icons.favorite_border,
color: doa.fav ? Colors.red : null,
),
onPressed: () =>
setState(() => doa.fav = !doa.fav),
)));
},
);
}
return CircularProgressIndicator();
})));
}
}
这是
preview
问题是,当您调用 setState 时,您 运行 再次构建,然后又 运行 使用原始 Doa 对象再次构建 FutureBuilder。
您需要在构建方法之外保留一个变量来保存 _MainPageState 中的更改,有几种方法可以做到这一点,在您的情况下它稍微复杂一些,因为您需要 fetchDoa 中的上下文。
一个解决方法是创建一个 doaList 变量来保存构建外部获取的数据,并更改 fetchDoa 函数以设置 doaList 而不是返回它(这就是为什么它现在是 Future 的原因。
但这还不够,因为 FutureBuilder 只会在每次构建 运行s 时从头开始设置 doaList,因此我们将添加一个 _isInit 布尔值来检查它是否是第一次 运行ning 构建。 之后你应该用 doaList 替换所有 'snapshot.data' 因为快照没有任何内容
class _MainPageState extends State<MainPage> {
List<Doa> doaList;
bool _isInit = true;
Future<void> fetchDoa(BuildContext context) async {
final jsonstring =
await DefaultAssetBundle.of(context).loadString('assets/doa.json');
doaList = doaFromJson(jsonstring);
_isInit = false;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("JSON Data test"),
),
body: Container(
child: FutureBuilder(
future: _isInit? fetchDoa(context): Future(),
builder: (context, _) {
试试这个,告诉我它是否有效:)
我制作了 JSON 数据并使用 ListView.builder 小部件将其显示在 FutureBuilder 中。我想在ListView.builder的尾部创建一个喜欢的Icon。所以我用 IconButton 创建了它,但是当我创建 setState 使某些项目成为收藏夹时,数据没有更新。
这是我的代码
import 'package:flutter/material.dart';
import 'package:json_test/class/doa.dart';
import 'package:json_test/page/DoaPage.dart';
class MainPage extends StatefulWidget {
@override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
Future<List<Doa>> fetchDoa(BuildContext context) async {
final jsonstring =
await DefaultAssetBundle.of(context).loadString('assets/doa.json');
return doaFromJson(jsonstring);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("JSON Data test"),
),
body: Container(
child: FutureBuilder(
future: fetchDoa(context),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
Doa doa = snapshot.data[index];
return Card(
margin: EdgeInsets.all(8),
child: ListTile(
title: Text(doa.judul),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) =>
DoaPage(
doa: doa,
)));
},
trailing: IconButton(
icon: Icon(
doa.fav
? Icons.favorite
: Icons.favorite_border,
color: doa.fav ? Colors.red : null,
),
onPressed: () =>
setState(() => doa.fav = !doa.fav),
)));
},
);
}
return CircularProgressIndicator();
})));
}
}
这是 preview
问题是,当您调用 setState 时,您 运行 再次构建,然后又 运行 使用原始 Doa 对象再次构建 FutureBuilder。
您需要在构建方法之外保留一个变量来保存 _MainPageState 中的更改,有几种方法可以做到这一点,在您的情况下它稍微复杂一些,因为您需要 fetchDoa 中的上下文。
一个解决方法是创建一个 doaList 变量来保存构建外部获取的数据,并更改 fetchDoa 函数以设置 doaList 而不是返回它(这就是为什么它现在是 Future 的原因。 但这还不够,因为 FutureBuilder 只会在每次构建 运行s 时从头开始设置 doaList,因此我们将添加一个 _isInit 布尔值来检查它是否是第一次 运行ning 构建。 之后你应该用 doaList 替换所有 'snapshot.data' 因为快照没有任何内容
class _MainPageState extends State<MainPage> {
List<Doa> doaList;
bool _isInit = true;
Future<void> fetchDoa(BuildContext context) async {
final jsonstring =
await DefaultAssetBundle.of(context).loadString('assets/doa.json');
doaList = doaFromJson(jsonstring);
_isInit = false;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("JSON Data test"),
),
body: Container(
child: FutureBuilder(
future: _isInit? fetchDoa(context): Future(),
builder: (context, _) {
试试这个,告诉我它是否有效:)