Flutter 상태 관리에 대하여 알아보자.
- Developer/Flutter
- 2023. 7. 1.
Flutter는 UI를 구성하는 코드와 상태를 관리하는 코드가 다른 언어와는 달리 동일한 언어로 작성되어 자연스러운 코드 구조를 갖고 있습니다. 그리고 마찬가지로 상태 관리도 다른 언어에서와 마찬가지로 중요하며 관심사 분리와 같은 개념에 따라 구현을 해야 합니다.
이번 글에서는 Flutter에서 기본적인 상태 관리 방식에 대해 살펴보고, 주요 상태 관리 라이브러리인 Provider, BLoC, GetX, Riverpod에 대해 간략하게 살펴볼까요?
1. Flutter의 기본적인 상태 관리
Flutter는 기본적으로 상위 Widget에서 하위 Widget으로 상태를 전달하고, 하위 Widget에서는 이벤트를 상위 Widget으로 전달하는 단방향 데이터 흐름의 구조를 가지고 있습니다.
이를 통해 앱 내부에서 각각의 위젯이 독립적으로 운영되며, 필요한 데이터를 쉽게 가져와서 사용할 수 있습니다. 상태를 변경해야 하는 경우에는 상위 위젯이 리빌드 될 수 있도록 setState 메소드를 이용하여 상태 변경을 동기화합니다.
class ExampleWidget extends StatefulWidget {
@override
_ExampleWidgetState createState() => _ExampleWidgetState();
}
class _ExampleWidgetState extends State<ExampleWidget> {
int _count = 0;
void _incrementCounter() {
setState(() {
_count++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('$_count'),
ElevatedButton(
onPressed: _incrementCounter,
child: Text('Increment'),
),
],
);
}
}
2. Provider
Provider는 Flutter의 공식 상태 관리 라이브러리 중에서 가장 많이 사용되고 있는 라이브러리 중 하나입니다.
Provider는 의존성 주입(Dependency Injection)을 위한 패키지로, 앱 전체에서 상태를 효율적으로 관리할 수 있도록 도와줍니다. Provider를 사용하면, 데이터를 손쉽게 모든 위젯에서 사용할 수 있고, 그것에 의존하는 모듈들이 간단하게 변경될 수 있어 유지보수와 대규모 코드에 용이합니다.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class ExampleWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => CountModel(),
child: Column(
children: [
Consumer<CountModel>(
builder: (context, model, child) {
return Text('${model.count}');
},
),
ElevatedButton(
onPressed: () {
Provider.of<CountModel>(context, listen: false)
.incrementCount();
},
child: Text('Increment'),
),
],
),
);
}
}
class CountModel with ChangeNotifier {
int count = 0;
void incrementCount() {
count++;
notifyListeners();
}
}
3. BLoC
BLoC는 Business Logic Component의 약자로, 상태 관리와 비즈니스 로직을 분리하도록 구성된 패턴입니다.
BLoC 패턴은 입력 값(이벤트)을 받아 처리하고, 그 처리 결과를 출력 값(상태)으로 보내는 단방향 패턴이며, 뷰에서 입력 값에 대한 처리 결과를 참조하는 방식입니다. BLoC로 앱을 작성하면, 뷰와 비즈니스 로직이 분리되므로 쉬운 테스트와 유지보수를 할 수 있습니다.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class ExampleWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => CountBloc(),
child: Column(
children: [
BlocBuilder<CountBloc, int>(
builder: (context, count) {
return Text('$count');
},
),
ElevatedButton(
onPressed: () {
context.read<CountBloc>().add(IncrementCount());
},
child: Text('Increment'),
),
],
),
);
}
}
class CountBloc extends Bloc<CountEvent, int> {
CountBloc() : super(0);
@override
Stream<int> mapEventToState(CountEvent event) async* {
if (event is IncrementCount) {
yield state + 1;
}
}
}
abstract class CountEvent {}
class IncrementCount extends CountEvent {}
4. GetX
GetX는 Flutter에서 상태 관리, 의존성 주입, 라우팅 등을 지원하는 패키지 중에 하나입니다.
GetX는 Flutter에서 여러 개의 위젯 또는 페이지 간에 빠르고 간단하게 데이터를 공유할 수 있도록 해줍니다. GetX는 Provider와 달리 여러 개의 상태를 합치거나 변경사항을 알릴 필요 없이 간편하게 사용할 수 있습니다.
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class ExampleWidget extends StatelessWidget {
final Controller controller = Get.put(Controller());
@override
Widget build(BuildContext context) {
return Obx(() => Column(
children: [
Text('${controller.count.value}'),
ElevatedButton(
onPressed: () {
controller.incrementCount();
},
child: Text('Increment'),
),
],
),
);
}
}
class Controller extends GetxController {
var count = 0.obs;
void incrementCount() {
count++;
}
}
5. Riverpod
Riverpod는 Provider 패키지를 계승한 새로운 Flutter 상태 관리 패키지입니다. Riverpod는 Provider와 비슷한 의존성 주입을 지원하기 때문에, 기존 Provider를 사용하던 개발자들이 쉽게 전환할 수 있습니다. Riverpod는 기존 Provider가 지원하지 않았던 지연 생성(lazy loading)과 비동기 의존성 주입, 데이터 바인딩 기능을 추가하여 더욱 강력한 상태 관리 라이브러리라 할 수 있습니다.
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final countProvider = StateNotifierProvider((_) => CountModel());
class ExampleWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, ScopedReader watch) {
final _count = watch(countProvider.state);
return Column(
children: [
Text('$_count'),
ElevatedButton(
onPressed: () {
context.read(countProvider).incrementCount();
},
child: Text('Increment'),
),
],
);
}
}
class CountModel extends StateNotifier<int> {
CountModel() : super(0);
void incrementCount() {
state++;
}
}
이상으로 Flutter의 상태 관리에 대한 간략한 소개였습니다.
각 라이브러리마다 장단점이 있으니 개발자 자신의 취향과 프로젝트에 맞게 적절한 상태 관리 라이브러리를 선택하는 것이 중요합니다. 어느 방법을 사용하더라도, 관심사 분리와 유지보수 가능성을 고려하여 구현하면 좋겠군요. 그럼 건강하시고 즐거운 코딩 되세요!
'Developer > Flutter' 카테고리의 다른 글
| <Flutter> 스마트폰 화면에 맞춰 UI 만들기 (0) | 2023.07.05 |
|---|---|
| <Flutter> Padding과 Margin (0) | 2023.07.04 |
| <Flutter> 위젯을 만들 때 자주 발생하는 에러와 해결 방법 (0) | 2023.07.04 |
| <Flutter> 기본 위젯 공부하기 (0) | 2023.07.03 |
| <Flutter> sqflite 기본 사용법 (0) | 2023.07.03 |