State Management
Flutter에서 상태 관리는 애플리케이션의 UI와 데이터 상태를 동기화하고 유지하는 중요한 개념입니다. 다양한 상태 관리 기법이 있으며, 각각의 방법은 특정 요구사항과 복잡도에 따라 선택할 수 있습니다. 여기에서는 Flutter의 주요 상태 관리 기법들을 소개하겠습니다.
1. setState
가장 기본적인 상태 관리 방법으로, StatefulWidget을 사용하여 상태를 관리합니다. 작은 애플리케이션이나 간단한 위젯에서 사용하기 적합합니다.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: CounterPage(),
);
}
}
class CounterPage extends StatefulWidget {
@override
_CounterPageState createState() => _CounterPageState();
}
class _CounterPageState extends State<CounterPage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Counter'),
),
body: Center(
child: Text(
'Counter: $_counter',
style: TextStyle(fontSize: 24),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
child: Icon(Icons.add),
),
);
}
}
2. Provider
Provider는 중간 복잡도의 애플리케이션에서 상태 관리를 더 쉽게 할 수 있도록 도와주는 패키지입니다. InheritedWidget을 기반으로 하며, 상태를 공유하고 하위 위젯 트리에 전파합니다.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => Counter(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: CounterPage(),
);
}
}
class Counter extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = Provider.of<Counter>(context);
return Scaffold(
appBar: AppBar(
title: Text('Counter'),
),
body: Center(
child: Text(
'Counter: ${counter.count}',
style: TextStyle(fontSize: 24),
),
),
floatingActionButton: FloatingActionButton(
onPressed: counter.increment,
child: Icon(Icons.add),
),
);
}
}
3. Riverpod
Riverpod은 Provider의 개선된 버전으로, 더 안전하고 테스트하기 쉬운 상태 관리를 제공합니다.
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: CounterPage(),
);
}
}
final counterProvider = StateProvider<int>((ref) => 0);
class CounterPage extends ConsumerWidget {
@override
Widget build(BuildContext context, ScopedReader watch) {
final counter = watch(counterProvider).state;
return Scaffold(
appBar: AppBar(
title: Text('Counter'),
),
body: Center(
child: Text(
'Counter: $counter',
style: TextStyle(fontSize: 24),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => context.read(counterProvider).state++,
child: Icon(Icons.add),
),
);
}
}
4. Bloc
Bloc은 Business Logic Component의 약자로, 이벤트 기반 상태 관리를 제공합니다. 대규모 애플리케이션에서 사용하기 적합하며, 상태와 비즈니스 로직을 분리합니다.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: BlocProvider(
create: (_) => CounterBloc(),
child: CounterPage(),
),
);
}
}
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0);
@override
Stream<int> mapEventToState(CounterEvent event) async* {
if (event is Increment) {
yield state + 1;
}
}
}
abstract class CounterEvent {}
class Increment extends CounterEvent {}
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counterBloc = BlocProvider.of<CounterBloc>(context);
return Scaffold(
appBar: AppBar(
title: Text('Counter'),
),
body: Center(
child: BlocBuilder<CounterBloc, int>(
builder: (context, count) {
return Text(
'Counter: $count',
style: TextStyle(fontSize: 24),
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
counterBloc.add(Increment());
},
child: Icon(Icons.add),
),
);
}
}
5. GetX
GetX는 경량화된 상태 관리 패키지로, 상태 관리, 의존성 주입, 라우팅 등을 지원합니다. 간단하면서도 강력한 기능을 제공합니다.
import 'package:flutter/material.dart';
import 'package:get/get.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'Flutter Demo',
home: CounterPage(),
);
}
}
class CounterController extends GetxController {
var count = 0.obs;
void increment() {
count++;
}
}
class CounterPage extends StatelessWidget {
final CounterController controller = Get.put(CounterController());
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Counter'),
),
body: Center(
child: Obx(
() => Text(
'Counter: ${controller.count}',
style: TextStyle(fontSize: 24),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: controller.increment,
child: Icon(Icons.add),
),
);
}
}
결론
Flutter에서 상태 관리는 애플리케이션의 규모와 복잡도에 따라 다양한 방법을 사용할 수 있습니다. 간단한 애플리케이션에서는 setState
를, 중간 복잡도에서는 Provider
나 Riverpod
을, 대규모 애플리케이션에서는 Bloc
이나 GetX
를 사용하는 것이 일반적입니다. 각 방법의 장단점을 고려하여 적절한 상태 관리 방법을 선택하는 것이 중요합니다.