dart bloc (basic / cubit)

Sunny·2022년 6월 7일

Bloc 사용 시 비즈니스 로직에서 presentation을 분리하기 쉽게 만듬! 코드를 빠르고 쉽게 테스트할 수 있고, 재사용할 수 있음

데이터 기반 의사결정 가능 => 단일 유저 상호작용을 기록하기에!!

가능한 한 효율적으로 작업하고 어플리케이션 내에서와 다른 어플리케이션에서 구성 요소 재사용!!

bloc의 3요소
simple : 이해하기 쉽고 다양한 기술 수즌을 가진 것을 사용할 수 있음
Powerful: 더 작은 구서용소로 구성 / 복잡한 응용프로그램 만드는데 도움!!
Testable: 어플리케이션의 모든 측면을 쉽게 test => 반복할 수 있음!!

stream (비동기 데이터의 시퀀스)

(익숙치 않다면 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
}

cubit (blocbase를 상속받는 class / state의 상태를 관리할 수 있음)

cubit

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 재정의 전에 호출
profile
즐거움을 만드는 사람

0개의 댓글