Usage of FutureBuilder with setState

前端 未结 2 1062
时光说笑
时光说笑 2020-12-16 13:22

How to use the FutureBuilder with setState properly? For example, when i create a stateful widget its starting to load data (FutureBuilder) and the

相关标签:
2条回答
  • 2020-12-16 13:31

    Use can SchedulerBinding for using setState() inside Future Builders or Stream Builder,

     SchedulerBinding.instance
                    .addPostFrameCallback((_) => setState(() {
                  isServiceError = false;
                  isDataFetched = true;
                }));
    
    0 讨论(0)
  • 2020-12-16 13:40

    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,
                ),
              );
            }
          },
        );
      }
    }
    
    0 讨论(0)
提交回复
热议问题