Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
914 views
in Technique[技术] by (71.8m points)

dart - Usage of FutureBuilder with 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,
                ),
              );
        }
      },
    );
  }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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!


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.

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...