如何使用FutureBuilder与setState正常吗?例如,当我创建一个有状态的小部件时,它开始加载数据(FutureBuilder),然后我应该用新数据更新列表,所以我使用setState,但是它开始循环到无限(因为我再次重建了小部件),任何解决方案?
FutureBuilder
setState
class FeedListState extends State<FeedList> { Future<Null> updateList() async { await widget.feeds.update(); setState(() { widget.items = widget.feeds.getList(); }); //widget.items = widget.feeds.getList(); } @override Widget build(BuildContext context) { return new FutureBuilder<Null>( future: updateList(), builder: (BuildContext context, AsyncSnapshot<String> snapshot) { switch (snapshot.connectionState) { case ConnectionState.waiting: return new Center( child: new CircularProgressIndicator(), ); default: if (snapshot.hasError) return new Text('Error: ${snapshot.error}'); else return new Scrollbar( child: new RefreshIndicator( child: ListView.builder( physics: const AlwaysScrollableScrollPhysics(), //Even if zero elements to update scroll itemCount: widget.items.length, itemBuilder: (context, index) { return FeedListItem(widget.items[index]); }, ), onRefresh: updateList, ), ); } }, ); } }
确实,它将循环到无穷大,因为无论何时build被调用,updateList也被调用并返回全新的未来。
build
updateList
你必须保持build纯洁。它应该只读取并组合变量和属性,但绝不会引起任何副作用!
另一个注意事项:StatefulWidget子类的所有字段都必须为final(widget.items = ...不好)。更改的状态必须存储在State对象中。
StatefulWidget
widget.items = ...
State
在这种情况下,您可以将结果(列表中的数据)存储在将来的本身中,而无需单独的字段。setState从将来调用它甚至很危险,因为将来可能会在处置状态之后完成,并且会引发错误。
这是一些考虑了所有这些因素的更新代码:
class FeedListState extends State<FeedList> { // no idea how you named your data class... Future<List<ItemData>> _listFuture; @override void initState() { super.initState(); // initial load _listFuture = updateAndGetList(); } void refreshList() { // reload setState(() { _listFuture = updateAndGetList(); }); } Future<List<ItemData>> updateAndGetList() async { await widget.feeds.update(); // return the list here return widget.feeds.getList(); } @override Widget build(BuildContext context) { return new FutureBuilder<List<ItemData>>( future: _listFuture, builder: (BuildContext context, AsyncSnapshot<List<ItemData>> snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return new Center( child: new CircularProgressIndicator(), ); } else if (snapshot.hasError) { return new Text('Error: ${snapshot.error}'); } else { final items = snapshot.data ?? <ItemData>[]; // handle the case that data is null return new Scrollbar( child: new RefreshIndicator( child: ListView.builder( physics: const AlwaysScrollableScrollPhysics(), //Even if zero elements to update scroll itemCount: items.length, itemBuilder: (context, index) { return FeedListItem(items[index]); }, ), onRefresh: refreshList, ), ); } }, ); } }