The Flutter FutureBuilder is a great example of Flutters composability with widgets. It allows us to wrap a Future, an async operation, and easily render the three different states, loading, error or result.

However, this turned out to be less straightforward than I thought it would be and I did a deep dive to figure out why.

Reloading the FutureBuilder future

Maybe you don’t care why and just want to know how? That’s fine to, this is my solution, how to properly get the FutureBuilder to allow you to change a future and re-render a loading state whilst the future is processing:

final builder = FutureBuilder(
    future: _future,
    builder: (context, snapshot) {
      if (snapshot.connectionState != ConnectionState.done) {
        return _buildLoader();
      }
      if (snapshot.hasError) {
        return _buildError();
      }
      if (snapshot.hasData) {
        return _buildDataView();
      }     
      return _buildNoData();
});

The hasData is not reset

My initial solution was simpler, like this:

return FutureBuilder(
        future: _future,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return Text("Result: ${snapshot.data}");
          }
          if (snapshot.hasError) {
            return Text(snapshot.error.toString());
          }
          return Text("Loading..");
        });

Problem is, the hasData and hasError simply aren’t reset when the future changes, only the connectionState is. We can see this if we break out the FutureBuilder source code:

  @override
  void didUpdateWidget(FutureBuilder<T> oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.future != widget.future) {
      if (_activeCallbackIdentity != null) {
        _unsubscribe();
        // Snapshot state is reset here
        _snapshot = _snapshot.inState(ConnectionState.none);
      }
      _subscribe();
    }
  }

The full break down

I reproduced this, issue and solution in a small GitHub project so you can see the code in entirety with a running example of how it works:

https://github.com/ddikman/flutter-rerunnable-future-builder

Working example of the FutureBuilder with a replaced future

I hope it helps!