setState对FutureBuilder的使用 [英] Usage of FutureBuilder with setState

查看:191
本文介绍了setState对FutureBuilder的使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在 setState 中正确使用 FutureBuilder ?例如,当我创建一个有状态的小部件时,它开始加载数据(FutureBuilder),然后我应该用新数据更新列表,因此我使用setState,但是它开始循环到无限(因为我再次重建了小部件),任何解决方案?

How to use the FutureBuilder with setState properly? For example, when i create a stateful widget its starting to load data (FutureBuilder) and then i should update the list with new data, so i use setState, but its starting to loop for infinity (because i rebuild the widget again), any solutions?

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 并返回崭新的未来。

Indeed, it will loop into infinity because whenever build is called, updateList is also called and returns a brand new future.

您必须保持版本纯净。它应该只读取并组合变量和属性,但绝不会引起任何副作用!

You have to keep your build pure. It should just read and combine variables and properties, but never cause any side effects!

另一注:您的所有字段 StatefulWidget 子类必须是最终子类( widget.items = ... 不好)。更改状态必须存储在 State 对象中。

Another note: All fields of your StatefulWidget subclass must be final (widget.items = ... is bad). The state that changes must be stored in the State object.

在这种情况下,您可以存储结果(列表中的数据),以后就不需要单独的字段了。从将来调用 setState 甚至很危险,因为将来可能会在处置状态后完成,并且会引发错误。

In this case you can store the result (the data for the list) in the future itself, there is no need for a separate field. It's even dangerous to call setState from a future, because the future might complete after the disposal of the state, and it will throw an error.

以下是一些考虑到所有这些问题的更新代码:

Here is some update code that takes into account all of these things:

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,
            ),
          );
        }
      },
    );
  }
}

这篇关于setState对FutureBuilder的使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆