Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Learn FutureBuilder Done Right | Real Data in UI
Flutter REST API Integration

bookFutureBuilder Done Right

When working with asynchronous API data in Flutter, the FutureBuilder widget is your go-to solution for integrating real-time responses into your UI. FutureBuilder listens to a Futureβ€”such as an HTTP requestβ€”and rebuilds your widget tree based on the Future's state. This lets you elegantly display loading spinners, error messages, or the fetched data, all within a single widget. Using FutureBuilder ensures that your app remains responsive and provides clear feedback to users as data loads, fails, or is empty.

Note
Note

Handling all possible states, loading, error, and empty, is critical for a polished user experience. Ignoring any of these can leave users confused or frustrated, as they may not know whether data is still loading, something went wrong, or simply no data is available. Always provide clear feedback for each state to make your app feel responsive and reliable.

main.dart

main.dart

copy
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
import 'package:flutter/material.dart'; import 'dart:convert'; import 'package:http/http.dart' as http; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'FutureBuilder Demo', home: Scaffold( appBar: AppBar(title: Text('Users List')), body: UsersList(), ), ); } } class UsersList extends StatelessWidget { Future<List<String>> fetchUsers() async { final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/users')); if (response.statusCode != 200) { throw Exception('Failed to load users'); } final List<dynamic> data = json.decode(response.body); if (data.isEmpty) { return []; } return data.map((user) => user['name'] as String).toList(); } @override Widget build(BuildContext context) { return FutureBuilder<List<String>>( future: fetchUsers(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { return Center(child: Text('Error: [${snapshot.error}')); } else if (!snapshot.hasData || snapshot.data!.isEmpty) { return Center(child: Text('No users found.')); } else { final users = snapshot.data!; return ListView.builder( itemCount: users.length, itemBuilder: (context, index) => ListTile( title: Text(users[index]), ), ); } }, ); } }

In the code above, FutureBuilder manages three main UI states based on the progress and result of the API call. When the Future is still loading, a CircularProgressIndicator is shown to indicate that data is being fetched. If the Future completes with an error, an error message is displayed using the error details. If the API call succeeds but returns an empty list, a message stating "No users found." is presented. When data is successfully fetched and not empty, the list of user names is displayed in a ListView. This approach ensures users always know what is happening with the data load process.

question mark

What state should you always handle when displaying API data with FutureBuilder?

Select the correct answer

Everything was clear?

How can we improve it?

Thanks for your feedback!

SectionΒ 2. ChapterΒ 1

Ask AI

expand

Ask AI

ChatGPT

Ask anything or try one of the suggested questions to begin our chat

bookFutureBuilder Done Right

Swipe to show menu

When working with asynchronous API data in Flutter, the FutureBuilder widget is your go-to solution for integrating real-time responses into your UI. FutureBuilder listens to a Futureβ€”such as an HTTP requestβ€”and rebuilds your widget tree based on the Future's state. This lets you elegantly display loading spinners, error messages, or the fetched data, all within a single widget. Using FutureBuilder ensures that your app remains responsive and provides clear feedback to users as data loads, fails, or is empty.

Note
Note

Handling all possible states, loading, error, and empty, is critical for a polished user experience. Ignoring any of these can leave users confused or frustrated, as they may not know whether data is still loading, something went wrong, or simply no data is available. Always provide clear feedback for each state to make your app feel responsive and reliable.

main.dart

main.dart

copy
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
import 'package:flutter/material.dart'; import 'dart:convert'; import 'package:http/http.dart' as http; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'FutureBuilder Demo', home: Scaffold( appBar: AppBar(title: Text('Users List')), body: UsersList(), ), ); } } class UsersList extends StatelessWidget { Future<List<String>> fetchUsers() async { final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/users')); if (response.statusCode != 200) { throw Exception('Failed to load users'); } final List<dynamic> data = json.decode(response.body); if (data.isEmpty) { return []; } return data.map((user) => user['name'] as String).toList(); } @override Widget build(BuildContext context) { return FutureBuilder<List<String>>( future: fetchUsers(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { return Center(child: Text('Error: [${snapshot.error}')); } else if (!snapshot.hasData || snapshot.data!.isEmpty) { return Center(child: Text('No users found.')); } else { final users = snapshot.data!; return ListView.builder( itemCount: users.length, itemBuilder: (context, index) => ListTile( title: Text(users[index]), ), ); } }, ); } }

In the code above, FutureBuilder manages three main UI states based on the progress and result of the API call. When the Future is still loading, a CircularProgressIndicator is shown to indicate that data is being fetched. If the Future completes with an error, an error message is displayed using the error details. If the API call succeeds but returns an empty list, a message stating "No users found." is presented. When data is successfully fetched and not empty, the list of user names is displayed in a ListView. This approach ensures users always know what is happening with the data load process.

question mark

What state should you always handle when displaying API data with FutureBuilder?

Select the correct answer

Everything was clear?

How can we improve it?

Thanks for your feedback!

SectionΒ 2. ChapterΒ 1
some-alt