Flutter로 처음 개발 할 때 BLoC 패턴으로 입문해서 그런지, 아무리 불편해도 BLoC 패턴을 자주 사용한다.
(최근에 GetX를 써보니, dependency injection 부분이 정말 신세계였다...😭)
처음 시작 당시에는 flutter version이 1.2xx 이기도 했었고 해서,
이번에는 flutter 2.xx로 업그레이드하고 코딩을 하고 있는데 기존에 사용했던 코드가 안먹히는 ㅎㅎ; 상태가 발생했다.
null-safefy 추가와 함께 BLoC에서는 어떠한 변화가 있는지, 알아본 것을 바탕으로 글을 써본다.
1. BlocBase
bloc 패키지에서 상태를 관리하는 방법으로 Bloc과 Cubit을 제시하고 있습니다.
Cubit은 이벤트의 개념이 없이, state를 가볍게 관리 할 수 있는 개념으로 사용되었는데요,
기존에는 Bloc class와 Cubit class가 각각으로 존재했지만, 이제는 BlocBase라는 상위 클래스를 기반으로해서 extended 하는 형태로 바뀌었습니다.
기존)
abstract class Cubit<State> extends Stream<State> {
..
}
abstract class Bloc<Event, State> extends Cubit<State> implements EventSink<Event> {
..
}
변경 후)
abstract class BlocBase<State> {
}
abstract class Bloc<Event, State> extends BlocBase<State> {
/// {@macro bloc}
Bloc(State initialState) : super(initialState) {
_bindEventsToStates();
}
}
abstract class Cubit<State> extends BlocBase<State> {
/// {@macro cubit}
Cubit(State initialState) : super(initialState);
}
이번 업데이트를 통해 Cubit과 Bloc의 쓰임을 명확하게 나눈 듯한 느낌을 줍니다.
기존에는 cubit과 bloc의 차이가 뭔지 몰라서, 그냥 더 직관(?)적인 cubit을 선호했었는데,
Bloc은 event 기반 state 관리 / Cubit은 (module 단위의) state 관리에 적합하다는 것을 알 수 있었습니다.
그리고 BlocBase 클래스의 등장으로, BlocObserver의 interface도 바뀌었으니, flutter 2.점대로 마이그레이션 하는 분들은 확인해보시길 바랍니다.
class BlocObserver {
void onCreate(BlocBase bloc) {}
void onEvent(Bloc bloc, Object? event) {}
void onChange(BlocBase bloc, Change change) {}
void onTransition(Bloc bloc, Transition transition) {}
void onError(BlocBase bloc, Object error, StackTrace stackTrace) {}
void onClose(BlocBase bloc) {}
}
2. null-safety 적용
null-safety 적용으로 인해, dependency injection 후 widget 초기화에서 조심(?)해야 할 것이 생겼습니다.
바로, 의존성 주입 받은 변수의 초기화 시점을 명확하게 선언해줘야 한다는 것인데요,
글로 이야기하면 확실하게 와닿지 않으니 아래 코드를 통해 살펴보겠습니다.
class PostsList extends StatefulWidget {
@override
_PostsListState createState() => _PostsListState();
}
class _PostsListState extends State<PostsList> {
final _scrollController = ScrollController();
PostBloc _postBloc;
// 에러 발생!
// 컴파일러가 변수 사용 가능하다는 것을 보증할 수 없기 때문에 _postBloc을 초기화 해야 함
@override
void initState() {
super.initState();
_scrollController.addListener(_onScroll);
_postBloc = context.read<PostBloc>();
}
위 코드를 보면, InitState 에서 초기화 했음에도 불구하고, 변수 선언 시 초기화 하지 않을 경우 에러를 뱉습니다.
따라서, 해당 BlocType을 Optional로 하거나 late 연산자를 사용해서 초기화 시점을 늦추는 방법으로 사용해야합니다.
class _PostsListState extends State<PostsList> {
final _scrollController = ScrollController();
late PostBloc _postBloc;
@override
void initState() {
super.initState();
_scrollController.addListener(_onScroll);
_postBloc = context.read<PostBloc>();
}
}
3. BlocSelector
BlocBuilder와 유사하지만, bloc 상태를 일부를 선택하여 변경될 때만 빌드하고,
bloc 파라미터를 생략한 경우 해당 컨텍스트에서 사용 중인 bloc을 자동으로 잡아서 사용한다고 합니다.
BlocSelector<BlocA, BlocAState, SelectedState>(
selector: (state) {
// return selected state based on the provided state.
},
builder: (context, state) {
// return widget here based on the selected state.
},
)
아직 사용해본 적이 없어서 잘은 모르겠지만, 무분별한 build를 방지 할 수 있어 퍼포먼스적인 측면에서 도움이 되지 않을까.. 하는 짧은 생각이 듭니다.
flutter_bloc 관련해서는 이 정도가 주요 업데이트인 것 같습니다.
그 외에 bloc_test 패키지 쪽으로 많은 업데이트가 있었는데요. 관련해서 테스트 쪽을 사용해보고 다음에 포스팅 해보도록 하겠습니다 ✌️
--
참고
'✏️ > Flutter' 카테고리의 다른 글
[flutter] 내 프로젝트가 다른 사이트에 소개된.ssul (1) | 2021.11.08 |
---|---|
[flutter] 새로운 Bloc Widget 두둥 등장! - BlocSelector (0) | 2021.08.20 |
[flutter][Getx] GetX pattern 겟✊-하기 (구조) (0) | 2021.07.30 |
[flutter][Getx] GetX pattern 겟✊-하기 (구조) (0) | 2021.07.29 |
[flutter][GetX] 플러터 프로젝트 GetX로 겟-하기 - 1편, CLI (0) | 2021.07.27 |