Bidev
IntermediateAsync Programming

What are the common pitfalls of using FutureBuilder?

Short Answer

The most common FutureBuilder bug is passing a new Future instance on every build (e.g. calling a function directly in the future: parameter), which re-triggers the loading state on every rebuild instead of just once.

FutureBuilder re-runs its builder whenever the widget rebuilds, but only actually re-fetches if the future instance it's given is a different Future than last time. Writing future: fetchData() directly inside build() creates a brand-new Future object on every rebuild — even ones triggered by unrelated state changes — causing the UI to flash back to a loading spinner repeatedly.

The fix is to create the Future once (in initState, or a stored state variable) and pass that same stored reference into future: on every build. This is conceptually the same fix as a common useEffect dependency-array mistake in React.

Code Example

class _MyWidgetState extends State<MyWidget> {
  late final Future<Data> _future = fetchData(); // created once

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<Data>(
      future: _future, // stable reference across rebuilds
      builder: (context, snapshot) { /* ... */ return const SizedBox(); },
    );
  }
}

Common Mistakes

  • ×Calling the async function directly inside the future: parameter on every build.
  • ×Not handling ConnectionState.none/waiting/done explicitly, leading to a flash of incorrect UI between states.

Interview Tips

  • This is a commonly-asked 'gotcha' — mentioning the new-Future-per-build issue signals real hands-on debugging experience.