상태관리 : bloc 과 provider에 대해서
이제 막 나만의 앱을 만들기 위해 플러터에 대해 공부중이다.
나의 기본 포지션 자체가 백엔드이기 때문에 플러터를 공부하면서 화면을 보면서 개발을 하니 뭔가 진짜 찐 개발자가 된 것 같은 느낌이랄까...?ㅎㅎㅎㅎ
백엔드 개발자로서 보통 db설계 및 api 개발을 위주로 하다보니 클라이언트 쪽에서 api를 받고 뿌려주는 것에 대해서는 무지하기 때문에 이번 기회를 통해 클라이언트쪽도 열심히 공부하자는 마인드이다.
그런데 클라이언트 쪽에서는 상태관리 라는 개념이 존재하는데, 이 상태관리가 굉장히 중요하다는 것을 알게 되었다. 예전에 리액트를 잠시 할때에도 setState 등의 개념이 있던걸로 얼핏 기억하는데, 플러터에서도 역시 상태관리 라는 개념이 있었기에 블로그로 기록하고자 한다.
1. BLoC
BLoC는 이벤트 기반 상태 관리 패턴을 사용한다. 이 패턴에서는 UI에서 이벤트가 발생하면 BLoC으로 전달되고, BLoC은 해당 이벤트를 처리한 후 상태를 업데이트 한다. UI쪽에서는 BLoC의 상태 변화를 감지하고 그에 따라 화면을 다시 그리게 된다.
해당 BLoC 의 특징은 크게 3가지 정도인데,
첫번째는 이벤트 기반 으로서 UI는 이벤트를 발생시키고, BLoC은 이 이벤트를 받아 로직을 처리하게 된다.
두번째는 스트림 기반으로 BLoC은 Dart의 스트림을 사용하여 상태변화를 관리한다.
세번째는 비즈니스 로직과 UI의 분리인데 BLoC는 비즈니스 로직을 UI로부터 분리하여 코드의 재사용성과 테스트 용이성을 향상시킨다.
아래에는 BLoC의 예시코드를 적어보았다.
// BLoC 정의
class CounterBloc {
int _counter = 0;
// Stream을 위한 컨트롤러
final _counterController = StreamController<int>();
// 외부에서 들을 수 있는 Stream
Stream<int> get counter => _counterController.stream;
// 이벤트 처리
void increment() {
_counter++;
_counterController.sink.add(_counter);
}
void dispose() {
_counterController.close();
}
}
// UI에서의 사용
class CounterPage extends StatelessWidget {
final CounterBloc bloc = CounterBloc();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Counter')),
body: StreamBuilder<int>(
stream: bloc.counter,
builder: (context, snapshot) {
return Center(
child: Text(
snapshot.hasData ? 'Count: ${snapshot.data}' : 'Loading...',
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: bloc.increment,
child: Icon(Icons.add),
),
);
}
}
2. Provider
provider는 간단하고 효율적인 상태관리를 위한 패키지로서 데이터의 변경을 감지하고 필요한 위젯들에게 데이터를 제공한다.
특징으로는,
첫번째는 간결성이다. Provider는 상태관리를 위한 비교적 간단한 방법을 제공한다.
두번째는 상태변화의 감지이다. Provider는 ChangeNotifier를 활용하여 상태 변화를 감지하고 관련된 위젯을 자동으로 다시 빌드한다.
세번째는 접근성이다. Provider는 상태를 필요로 하는 위젯에 쉽게 접근할 수 있도록 도와준다.
아래에는 Provider 사용에 대한 예시코드이다.
// ChangeNotifier를 확장한 모델
class CounterModel with ChangeNotifier {
int _counter = 0;
int get counter => _counter;
void increment() {
_counter++;
notifyListeners(); // 상태가 변경되었다고 알림
}
}
// UI에서의 사용
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Provider를 통한 상태 접근
final counterModel = Provider.of<CounterModel>(context);
return Scaffold(
appBar: AppBar(title: Text('Counter')),
body: Center(
child: Text('Count: ${counterModel.counter}'),
),
floatingActionButton: FloatingActionButton(
onPressed: counterModel.increment,
child: Icon(Icons.add),
),
);
}
}
3. 그래서 BLoC하고 Provider 하고 비교하자면?
- 복잡성 : BLoC는 스트림과 이벤트 처리를 통해 상태 관리를 수행하므로 Provider보다 훨씬 복잡하고 러닝커브도 길어서 뉴비들은 Provider를 사용하는게 정신건강에 이로울 수 있습니다.
- 적합한 사용 사례 : Provider는 간단한 상태 관리에 적합하며, BLoC는 더 크고 복잡한 애플리케이션의 상태 관리에 적합합니다.
- 아키텍쳐 : BLoC는 아키텍쳐와 코드 구조에 더 많은 규칙을 요구하기 때문에 복잡하지만, Provider는 이에 비해 좀 더 유연합니다.