FutureBuilder는 전달된 Future에서 얻은 AsyncSnapshot의 현재 상태에 따라 인터페이스를 자동으로 다시 빌드하는 Flutter 위젯입니다. await 후 수동으로 setState를 호출하는 것과 달리, FutureBuilder는 선언적 접근 방식을 제공합니다: 첫 렌더링 시 Future를 구독하고 로딩, 오류 또는 준비된 데이터 등 상태 변경마다 builder 함수를 호출합니다. Flutter API Reference (2026)에 따르면, FutureBuilder는 네트워크에서 데이터 로딩, 데이터베이스 읽기 및 UI가 로딩 표시기, 오류 메시지 또는 준비된 콘텐츠를 표시해야 하는 모든 비동기 작업에 특히 유용합니다.
핵심 사항
FutureBuilder는 widgets 패키지의 내장 Flutter 위젯으로 Future
데이터 스트림(Stream)으로 작업하는 StreamBuilder와 달리, FutureBuilder는 일회성 비동기 작업(HTTP 요청, 파일 읽기, 데이터베이스 쿼리)을 위해 설계되었습니다. FutureBuilder는 Future 구독을 자체적으로 관리합니다: 첫 빌드 시 Future를 시작하고 완료를 추적합니다. 위젯이 소멸될 때 FutureBuilder는 Future를 취소하지 않습니다 — 이는 개발자의 책임입니다.
Flutter Cookbook (2026)에 따르면, FutureBuilder는 화면 초기화 시 비동기 작업이 한 번 실행되는 경우에 권장됩니다. 반복 작업이나 데이터 스트림의 경우 StreamBuilder를 사용하세요. 두 위젯 모두 동일한 반응형 UI 패턴을 따르지만, FutureBuilder는 일회성 요청에 최적화되어 있습니다.
FutureBuilder의 내부 구현은 Future.then과 catchError를 사용하여 Future를 구독합니다. FutureBuilder가 시작되면 connectionState를 ConnectionState.waiting으로 설정하고 빈 데이터로 builder를 호출합니다. 성공적으로 완료되면 connectionState가 데이터와 함께 ConnectionState.done으로 변경됩니다. 오류 발생 시 snapshot.error가 오류 객체로 채워집니다. 각 변경 사항이 위젯 재빌드를 트리거합니다.
AsyncSnapshot은 FutureBuilder가 상태 변경마다 builder 함수에 전달하는 컨테이너 객체입니다. 여기에는 비동기 작업의 현재 상태(로딩 진행 중인지, 어떤 데이터를 수신했는지, 오류가 발생했는지)에 대한 모든 정보가 포함됩니다. AsyncSnapshot을 이해하는 것이 FutureBuilder로 UI를 올바르게 구축하는 핵심입니다.
| 속성 | 타입 | 설명 |
|---|---|---|
| connectionState | ConnectionState | 현재 연결 상태 (none, waiting, active, done) |
| data | T? | Future에서 수신한 데이터 (완료 전까지 또는 오류 시 null) |
| error | Object? | Future가 예외로 완료된 경우 오류 객체 |
| hasData | bool | data가 null이 아니고 connectionState가 ConnectionState.done이면 true |
| hasError | bool | Future가 오류로 완료되면 true |
ConnectionState 열거형은 비동기 작업의 단계를 정의합니다. None — Future가 아직 시작되지 않은 초기 상태(드물게 사용, 일반적으로 initialData 없이 첫 빌드 시). Waiting — Future가 실행 중, 데이터 아직 수신되지 않음. Active — 부분 데이터가 있는 스트림을 위해 StreamBuilder만 사용. Done — Future가 완료됨, 데이터는 snapshot.data 또는 오류는 snapshot.error로 사용 가능.
builder 함수에서 모든 AsyncSnapshot 상태를 적절히 처리하는 것은 프로덕션 코드의 필수 요구 사항입니다. waiting 상태를 처리하지 않으면 사용자가 로딩 중 빈 화면을 보게 됩니다. hasError를 처리하지 않으면 사용자가 설명 없는 예외를 받게 됩니다. 권장 패턴: hasError 확인 → hasData 확인 → 기본적으로 로딩 표시.
FutureBuilder는 여러 표준 패턴으로 사용될 수 있으며, 각각 특정 작업을 해결합니다. 주요 시나리오를 살펴보겠습니다: 초기화 시 데이터 로딩, 캐싱으로 로딩, 병렬 요청 및 재시도로 오류 처리.
가장 일반적인 패턴 — StatefulWidget 또는 StatelessWidget의 build 메서드에서 FutureBuilder 사용. Future는 initState에서 전달되거나 build에서 직접 생성됩니다. 재빌드마다 build 메서드에서 Future를 생성하지 않는 것이 중요합니다 — 이는 반복 요청으로 이어집니다. State 필드에 저장된 Future를 사용하세요.
반복 요청을 방지하기 위해 FutureBuilder를 CachedNetworkImage 또는 로컬 캐시와 결합할 수 있습니다. 첫 로딩 후 데이터는 메모리 또는 SharedPreferences에 저장되고, FutureBuilder는 네트워크에서 병렬로 새로고침하면서 캐시된 데이터를 즉시 표시합니다. 이는 즉각적인 응답을 통해 UX를 개선합니다.
pub.dev (2026)에 따르면, 캐싱은 특히 이미지와 데이터 목록에 중요합니다. CachedNetworkImageProvider와 FutureBuilder는 캐시된 이미지를 자동으로 표시하고, 없을 경우 다운로드된 파일 후 로딩 표시기를 표시합니다.
FutureBuilder와 setState를 통한 수동 상태 관리는 Flutter에서 비동기 UI를 위한 두 가지 접근 방식입니다. 각각 장점과 한계가 있습니다. 선택은 화면 복잡성과 비동기 작업 수에 따라 달라집니다.
FutureBuilder는 단순성에서 우위를 점합니다: 로딩 상태, 데이터 및 오류에 대한 필드를 선언할 필요가 없습니다 — 모든 것이 AsyncSnapshot을 통해 관리됩니다. 하나의 비동기 작업(하나의 HTTP 요청, 데이터베이스 읽기)이 있는 간단한 화면에 이상적입니다. 그러나 하나의 화면에 5개 이상의 비동기 작업이 있는 경우 FutureBuilder는 과도한 중첩을 만듭니다 — 결과적으로 중첩된 FutureBuilder의 “피라미드”가 생성됩니다.
수동 상태 플래그를 사용한 setState는 복잡한 로직에 더 많은 제어와 가독성을 제공합니다. 여러 종속 요청(사용자 로드 → 주문 로드 → 주문 세부정보 로드)이 있는 화면의 경우 ChangeNotifier 또는 Bloc과 함께 setState를 사용하는 것이 좋습니다. Flutter State Management Guide (2026)에 따르면, 복잡한 시나리오에서는 FutureBuilder보다 Riverpod 또는 Bloc이 권장됩니다. 이들은 로직과 프레젠테이션을 더 잘 분리하기 때문입니다.
REST API에서 사용자 목록을 로드하는 실용적인 FutureBuilder 예제를 살펴보겠습니다. 코드는 AsyncSnapshot의 세 가지 상태(로딩, 오류, 준비된 데이터)를 모두 올바르게 처리하는 방법을 보여줍니다.
class UserListPage extends StatefulWidget {
const UserListPage({super.key});
@override
State<UserListPage> createState() => _UserListPageState();
}
class _UserListPageState extends State<UserListPage> {
final Future<List<User>> usersFuture = UserRepository().fetchUsers();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('사용자')),
body: FutureBuilder<List<User>>(
future: usersFuture,
builder: (context, AsyncSnapshot<List<User>> snapshot) {
if (snapshot.hasError) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error_outline, size: 48, color: Colors.red),
const SizedBox(height: 16),
Text('오류: ${snapshot.error}'),
],
),
);
}
if (snapshot.hasData) {
final users = snapshot.data!;
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(backgroundImage: NetworkImage(users[index].avatarUrl)),
title: Text(users[index].name),
subtitle: Text(users[index].email),
);
},
);
}
return const Center(child: CircularProgressIndicator());
},
),
);
}
}
예제에서 FutureBuilder는 세 가지 상태를 모두 처리합니다. 오류 시 오류 메시지와 함께 아이콘이 표시됩니다. 성공적 로드 시 — 아바타와 이름이 있는 ListView. 로딩 중 — CircularProgressIndicator. Future는 클래스 필드로 선언되어 재빌드 시 반복 호출을 방지합니다. 이 패턴은 모바일 앱에서 FutureBuilder 사용 시나리오의 90%를 커버합니다.
자주 묻는 질문
FutureBuilder는 Future 상태 변경마다 builder를 호출합니다: 첫 번째는 생성 시(connectionState: none 또는 waiting), 두 번째는 완료 시(connectionState: done). 부모 위젯이 재빌드되면 FutureBuilder도 재빌드됩니다. 반복 호출을 방지하려면 Future가 build 메서드 외부에서 생성되었는지 확인하세요 — 그렇지 않으면 모든 build 호출이 새 Future를 생성합니다.
Future를 StatefulWidget 필드(initState)에 저장하거나 메모이제이션을 사용하세요. Future가 build 메서드 내에서 생성되면 모든 build 호출이 새 Future를 생성하고 FutureBuilder가 비동기 작업을 다시 시작합니다. StatelessWidget의 경우 cached_future 패키지나 keep-alive 위젯을 사용하여 재빌드와 관계없이 Future가 한 번만 실행되도록 하세요.
FutureBuilder는 일회성 비동기 작업(하나의 HTTP 요청, 하나의 데이터베이스 읽기)용으로 설계되었습니다. StreamBuilder는 시간이 지남에 따라 여러 값을 방출할 수 있는 데이터 스트림(채팅, 가격 업데이트, 위치 정보)으로 작업합니다. StreamBuilder는 부분 데이터를 위해 ConnectionState.active를 지원하지만, FutureBuilder는 waiting과 done만 지원합니다.
여러 병렬 Future의 경우 Future.wait를 사용하고 결과를 단일 FutureBuilder에 전달하세요. Future.wait는 Future 목록을 받아 Future를 반환합니다 — 모든 Future가 완료되면 builder가 결과 배열을 받습니다. 순차 요청의 경우 하나의 Future 내에서 Future.then 체인을 사용하거나 중첩된 FutureBuilder(가독성 낮음)를 사용하세요. 대안으로 여러 비동기 상태를 위해 AsyncValue가 있는 riverpod 패키지가 있습니다.
FutureBuilder는 Future를 자동으로 취소하지 않습니다. 취소하려면 async 패키지의 CancelableOperation 또는 State의 cancelled 플래그를 통한 사용자 정의 메커니즘을 사용하세요. dispose()에서 플래그를 설정하고 Future 완료 후 setState를 호출하기 전에 확인하세요. 대안으로 AutoDispose가 있는 riverpod 패키지를 사용하면 화면을 나갈 때 비동기 작업이 자동으로 취소됩니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.