
Flutter에서 데이터를 비동기적으로 가져올 때, Stateful 위젯에서 async/await를 사용하거나 Stateless 위젯에서 FutureBuilder를 사용하는 두 가지 접근 방식이 있다. 이 두 가지 방법은 각각의 장단점이 있으며, 어떤 상황에 적합한지에 따라 선택해야 한다.
Stateful 위젯에서는 데이터를 받아오기 위해 initState() 메서드에서 async/await를 사용하여 비동기 작업을 수행하는 것이 일반적이다.
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Stateful Widget Async Await')),
body: DataFetchExample(),
),
);
}
}
class DataFetchExample extends StatefulWidget {
_DataFetchExampleState createState() => _DataFetchExampleState();
}
class _DataFetchExampleState extends State<DataFetchExample> {
String data = 'Fetching data...';
void initState() {
super.initState();
fetchData();
}
Future<void> fetchData() async {
try {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'));
if (response.statusCode == 200) {
setState(() {
data = jsonDecode(response.body)['title'];
});
} else {
setState(() {
data = 'Failed to load data';
});
}
} catch (e) {
setState(() {
data = 'Error occurred: $e';
});
}
}
Widget build(BuildContext context) {
return Center(
child: Text(data),
);
}
}
initState() 메서드에서 async 작업을 수행하기 때문에 비동기 작업이 자동으로 시작된다.setState()를 사용하여 UI의 상태를 명확하게 업데이트할 수 있다.Stateless 위젯에서는 FutureBuilder를 사용하여 비동기 데이터를 가져온다. FutureBuilder는 비동기 작업의 완료 상태에 따라 UI를 자동으로 업데이트한다.
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Stateless Widget FutureBuilder')),
body: FutureDataFetch(),
),
);
}
}
class FutureDataFetch extends StatelessWidget {
Future<String> fetchData() async {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'));
if (response.statusCode == 200) {
return jsonDecode(response.body)['title'];
} else {
throw Exception('Failed to load data');
}
}
Widget build(BuildContext context) {
return FutureBuilder<String>(
future: fetchData(),
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) {
return Center(child: Text(snapshot.data!));
} else {
return Center(child: Text('No data found'));
}
},
);
}
}
FutureBuilder는 비동기 작업의 상태 변화를 자동으로 감지하여 적절한 UI를 보여준다.FutureBuilder가 자동으로 UI를 다시 빌드해준다.FutureBuilder도 함께 종료되기 때문에 메모리 누수의 위험이 적다.FutureBuilder도 재실행될 수 있어, 같은 데이터를 반복적으로 요청하게 될 수 있다.| 특징 | Stateful 위젯 + async/await | Stateless 위젯 + FutureBuilder |
|---|---|---|
| 상태 관리 | setState를 통해 명확하게 관리 가능 | 자동으로 상태 업데이트 |
| 코드 가독성 | 코드가 복잡해질 수 있음 | 간결하고 직관적인 코드 |
| 복잡한 작업 | 복잡한 비동기 작업과 상태 관리에 유리 | 단순한 비동기 작업에 적합 |
| 메모리 관리 | 잘못된 비동기 처리가 메모리 누수 가능성 증가 | 메모리 누수 위험이 적음 |
| UI 재빌드 | setState 호출 시에만 재빌드 | 부모 위젯이 재빌드될 때마다 Future가 재실행될 수 있음 |
Stateful 위젯 + async/await는 복잡한 상태 관리가 필요하거나 여러 개의 비동기 작업을 수행할 때 유리하다.
네트워크 호출과 같은 긴 비동기 작업을 수행할 때도 좋다.
로딩, 성공, 오류 상태를 개별적으로 제어하고 싶을 때 적합하다.
Stateless 위젯 + FutureBuilder는 간단한 비동기 작업을 처리하고 싶을 때 적합하다.
상태 관리가 필요 없고, 데이터가 한 번 로드된 후 변경되지 않는 경우에 유리하다.
비동기 작업과 UI가 단순한 경우 코드가 훨씬 간결하다.
결론적으로, 간단한 비동기 작업에는 FutureBuilder를 사용하는 것이 좋고, 복잡한 상태 관리나 비동기 작업을 수행할 때는 Stateful 위젯에서 async/await를 사용하는 것이 더 나은 선택이다.