Bloc 사용 시 비즈니스 로직에서 presentation을 분리하기 쉽게 만듬! 코드를 빠르고 쉽게 테스트할 수 있고, 재사용할 수 있음
데이터 기반 의사결정 가능 => 단일 유저 상호작용을 기록하기에!!
가능한 한 효율적으로 작업하고 어플리케이션 내에서와 다른 어플리케이션에서 구성 요소 재사용!!
bloc의 3요소
simple : 이해하기 쉽고 다양한 기술 수즌을 가진 것을 사용할 수 있음
Powerful: 더 작은 구서용소로 구성 / 복잡한 응용프로그램 만드는데 도움!!
Testable: 어플리케이션의 모든 측면을 쉽게 test => 반복할 수 있음!!
(익숙치 않다면 streams => 물이 흐르는 파이프에서 파이프 = stream , 물은 비동기 데이터)
Stream<int> countStream(int max) async* {
for (int i = 0; i < max; i++) {
yield i;
}
}
Future<int> sumStream(Stream<int> stream) async {
int sum = 0;
await for (int value in stream) {
sum += value;
}
return sum;
}
void main() async {
/// Initialize a stream of integers 0-9
Stream<int> stream = countStream(10);
/// Compute the sum of the stream of integers
int sum = await sumStream(stream);
// stream 과 sum이 돌아가면서 출력되고 마지막 sum이 print 된다
print(sum); // 45
}

state 변경의 트리거가 적용될 수 있도록 함수를 노출할 수 있음
상태는 큐빗의 출력값과 어플리케이션의 상태 중 하나를 나타낸다.
UI 컴포넌트는 상태를 통지받고 현재 상태에 따라 자신의 일부를 다시 그릴 수 있음!!
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
}
// Cubit의 스테이트 타입을 정의할 필요가 있음!,
// 복잡한 상황에서는 필요에 의해서 class 대신에
// primitive types(int,double,String, bool, dynamic)을 사용할 수 있음!!
class CounterCubit extends Cubit<int> {
CounterCubit(int initialState) : super(initialState);
}
// creating a cubit / state type 정의할 필요가 있음! =>
//cubit 관리 / counterCubit 상태를 나타내는 것은 int 더 복잡할 떄는 class 사용 ! /
//initialstate하게 설정할 수 있지만, 외부의 값을 받아드린다.
final cubitA = CounterCubit(0); // state starts at 0
final cubitB = CounterCubit(10); // state starts at 10
cubit의 상태 변경 (각각의 큐빗은 emit이라는 것으로 새로운 상태를 출력 가능!)
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
void increment() => emit(state + 1);
//외부로 호출하여 전달가능 / counterCubit 상태를 증가 시킴 / 이 메서드는 내부에서만 사용해야함
}
void main() {
final cubit = CounterCubit();
print(cubit.state); // 0
cubit.increment();
print(cubit.state); // 1
cubit.close();
}
Future<void> main() async {
final cubit = CounterCubit();
final subscription = cubit.stream.listen(print); // 1
//호출 시 이후의 상태 변경만 수신
cubit.increment();
await Future.delayed(Duration.zero);
//서브스크립션이 즉시 취소되지 않도록 추가
await subscription.cancel();
await cubit.close();
}
//subscription을 실행 => 각 상태 변경시 print 호출 / 그리고 명령어 호출! => 새로운 상태를 방출하는 기능, cancel
cubit (새로운 상태가 emit 될 때, change가 발생함 / observe 시킬 수 있음 => cubit에 변화를 주면서, onchange를 overriding 시킴 )
BlocObserver (블록 라이브러리를 사용하면, 한 곳에서 모든 변경사항을 엑세슬 할 수 있음! / 대규모 어플리케이션에서느 상당히 좋음!)
BlocObserver (블록 라이브러리를 사용하면, 한 곳에서 모든 변경사항을 엑세슬 할 수 있음! / 대규모 어플리케이션에서느 상당히 좋음!)
```dart
class SimpleBlocObserver extends BlocObserver {
@override
void onChange(BlocBase bloc, Change change) {
super.onChange(bloc, change);
print('${bloc.runtimeType} $change');
}
}
// 모든 변화에 대응하여 무언가를 할 수 있다면 blocObserver를 사용할 수 있음!!
// blocObserver를 확장하고 onChange 메서드를 재정의하기만 하면 됌!
void main() {
BlocOverrides.runZoned(
() {
CounterCubit()
..increment()
..close();
},
blocObserver: SimpleBlocObserver(),
);
}
Change { currentState: 0, nextState: 1 }
CounterCubit Change { currentState: 0, nextState: 1 }
// 내부 onchange 재정의가 먼저 호출된 후 blockObserver에서 onchange가 호출!
Error Handling (큐빗에는 오류가 발생했음을 나타내는 데 사용할 수 있는 addError 메서드가 있음)
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
void increment() {
addError(Exception('increment error!'), StackTrace.current);
emit(state + 1);
}
void onChange(Change<int> change) {
super.onChange(change);
print(change);
}
void onError(Object error, StackTrace stackTrace) {
print('$error, $stackTrace');
super.onError(error, stackTrace);
}
//onError는 큐빗 내에서 재정의하여 특정 큐빗에 대한 모든 오류를 처리할 수 있습니다.
//onError를 BlockObserver에서 재정의하여 보고된 모든 오류를 전체적으로 처리할 수도 있음
}
class SimpleBlocObserver extends BlocObserver {
void onChange(BlocBase bloc, Change change) {
super.onChange(bloc, change);
print('${bloc.runtimeType} $change');
}
void onError(BlocBase bloc, Object error, StackTrace stackTrace) {
print('${bloc.runtimeType} $error $stackTrace');
super.onError(bloc, error, stackTrace);
}
}
//onChange와 마찬가지로 내부 onError 재정의는 글로벌 BlocObserver 재정의 전에 호출