flutter / bloc

Sunny·2022년 6월 7일

dart에서 쓰이는 bloc package가 아닌 flutter에서 쓰이는 flutter_bloc 패키지에 관한 것임

flutter_bloc

Bloc Widget


BlocBuilder

bloc과 builder 기능을 사용하기 위한 flutter widget . block builder는 새 상태에 대한 응답으로 위젯 작성 처리, blocBuilder는 streamBuilder와 매우 유사하지만 필요한 보일러 플레이트 코드의 양을 줄기이 위한 더 간단한 api를 가지고 있음! / builder 함수는 잠재적으로 여러번 호출 될 수 있음 / state response => 위젯 return pure function

대화 상자 표시 등과 같은 상태 변경에 대해 수행하려면 blocListener를 참조!

블록 매개 변수를 생략하면, blocBuilder가 blocProvider 및 현재 buildcontext를 사용하여 자동으로 조회를 수행함


BlocBuilder<BlocA, BlocAState>(
    // blocProvider, BlocState
  builder: (context, state) {
    // return widget here based on BlocA's state
  }
)

// 단일 위젯으로 범위가 지정, 상위 blocProvider 및 
//현재 BuildContext를 통해 access 할 수 없는 bloc 제공하려는 경우에만 bloc 지정

BlocBuilder<BlocA, BlocAState>(
  bloc: blocA, // provide the local bloc instance
  builder: (context, state) {
    // return widget here based on BlocA's state
  }
)
// true를 return 하면, 빌더와 상태가 함꼐 호출 => 위잿 재구성
// false일 경우 return 하면, 상태와 함꼐 호출되지 않아 위젯 재구성하지 않음

BlocSelector

blocSelector는 blocBuilder와 유사히자만 블록 상태를 기준으로 새 값을 선택하여 업데이트를 필터링할 수 있는 위젯! / 값이 변경되지 않으면 불필요한 빌드 방지 / blocSelector가 builder를 다시 호출 여부는 결정하려면 값이 불변해야함!! => blocSelector 가 blockProvider 및 buildContext를 사용하여 조회를 자동으로 수행

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.
  },
)

BlocProvider

BlockProvider.of(context)를 통해 자식들에게 bloc을 제공하는 Flutter 위젯!
하위 tree 내의 여러 위젯에 bloc의 단일 instance를 제공할 수 있도록 종속성 주입 위젯(해당 객체를 클래스마다 인스턴스화 즉 생성하는 대신 클래스에 종속 객체를 주입)으로 사용
bloc provider를 사용하여 하위 트리 나머지 부분에 사용할 수 있는 새 블록을 만들어야 함! / BlockProvider는 블록을 만드는 역할을 하므로 block close를 자동으로 함!

기본값으로, blocProvider는 BlocProvidr.of(context)를 통해 bloc을 조회할 떄 Create 실행
위의 동작을 무시하고 즉시 실행하도록 하려면 lazy를 false로 설정

BlocProvider(
  lazy: false,
  create: (BuildContext context) => BlocA(),
  child: ChildA(),
);
//BlocProvider를 사용하여, 위젯 트리의 새 부분에 기존 bloc을 provide 할 수 있음 
// 기존 bloc을 새 path에 사용할 수 있어야 할 떄 가장 일반적으로 사용 
// blockProvider는 bloc create X => bloc을 자동으로 close하지 않음!
BlocProvider.value(
  value: BlocProvider.of<BlocA>(context),
  child: ScreenA(),
);

// with extensions
context.read<BlocA>();

// without extensions
BlocProvider.of<BlocA>(context)

MultiBlocProvider

MultiBlocProvider는 여러 blocProvider를 하나로 병합하는 widget
MultiBlocProvider는 가독성 향상 / 여러 BlocProvider를 중첩할 필요 x


BlocProvider<BlocA>(
  create: (BuildContext context) => BlocA(),
  child: BlocProvider<BlocB>(
    create: (BuildContext context) => BlocB(),
    child: BlocProvider<BlocC>(
      create: (BuildContext context) => BlocC(),
      child: ChildA(),
    )
  )
)

// to

MultiBlocProvider(
  providers: [
    BlocProvider<BlocA>(
      create: (BuildContext context) => BlocA(),
    ),
    BlocProvider<BlocB>(
      create: (BuildContext context) => BlocB(),
    ),
    BlocProvider<BlocC>(
      create: (BuildContext context) => BlocC(),
    ),
  ],
  child: ChildA(),
)

BlocListener

BlocListener는 BlocWidgetListener와 선택적 Bloc을 사용하고 Bloc의 상태 변화에 따라 Listener를 호출하는 위젯 (snackBar, navigation, dialog에 사용 => 상태 변경당 한번 발생하는 기능!!)
Listener는 BlocBuilder의 builder와 달리 각 상태 변경(initial state는 포함되지 않음)에 대해 한 번만 호출되며 무효함수임! / Bloc 매겨 변수 생략 시 BlocListener가 BlocProvider 및 현재 BuildContext를 사용하여 조회를 자동으로 수행

BlocListener<BlocA, BlocAState>(
  listener: (context, state) {
    // do stuff here based on BlocA's state
  },
  child: Container(),
)

//BlocProvider 및 현재 BuildContext를 통해 Access 할 수 없는 bloc을 제공하려는 경우에만 bloc 지정
BlocListener<BlocA, BlocAState>(
  bloc: blocA,
  listener: (context, state) {
    // do stuff here based on BlocA's state
  },
  child: Container()
)

// function을 선택적으로 호출하려면, listenWhen을 사용하면 된다. 
//listen 이전 bloc state와 현재 bloc state를 사용하고 있는 bool을 return 해줌 => 
//true라면 listener와 상태가 같이 호출 / false라면 함꼐 호출되지 않음

BlocListener<BlocA, BlocAState>(
  listenWhen: (previousState, state) {
    // return true/false to determine whether or not
    // to call listener with state
  },
  listener: (context, state) {
    // do stuff here based on BlocA's state
  },
  child: Container(),
)

MultiBlocListener

여러 BlocListener 위젯을 하나로 병합하는 위젯 / 가독성 향상 , 중첩할 필요 없음


BlocListener<BlocA, BlocAState>(
  listener: (context, state) {},
  child: BlocListener<BlocB, BlocBState>(
    listener: (context, state) {},
    child: BlocListener<BlocC, BlocCState>(
      listener: (context, state) {},
      child: ChildA(),
    ),
  ),
)

//to

MultiBlocListener(
  listeners: [
    BlocListener<BlocA, BlocAState>(
      listener: (context, state) {},
    ),
    BlocListener<BlocB, BlocBState>(
      listener: (context, state) {},
    ),
    BlocListener<BlocC, BlocCState>(
      listener: (context, state) {},
    ),
  ],
  child: ChildA(),
)


BlocConsumer

BlocConsumer 는 새로운 상태에 반응하기 위해 builder와 listener를 노출시킴 / 중첩된 blocListener 및 BlocBuilder와 유사하지만 코드의 양을 줄임
BlocConsumer는 UI를 재구성하고 bloc의 상태 변화에 대한 다른 대응을 실행하는 경우에만 사용해야함
BlocConsumer는 필수 BlocWidgetBuilde 및 BlocWidgetListener와 선택적 bloc, BlockBuilderCondition 및 BlocListenerCondition을 사용
bloc 매개 변수 생략시 BlocConsumer는 BlocProvider 및 현재 BuildContext를 사용하여 조회를 자동으로 수행

BlocConsumer<BlocA, BlocAState>(
  listener: (context, state) {
    // do stuff here based on BlocA's state
  },
  builder: (context, state) {
    // return widget here based on BlocA's state
  }
)

//선택적으로 ListenWhen과 buildWhen을 사용할 수 있음 
//listenWhen 과 buildWhen은 각각의 bloc state 변경에 대해 호출됌
// 각각 이전 상태와 현재 상태를 취하며, 빌더 및 listener 기능의 호출 여부를 결정하는 모음을 반환 
// Bloc Consumer가 초기화되면 이전 상태의 Bloc Consumer가 초기화 됌 / listenWhen과 buildWhen이 구현되지 않는 경우 기본적으로 true로 설정됌

BlocConsumer<BlocA, BlocAState>(
  listenWhen: (previous, current) {
    // return true/false to determine whether or not
    // to invoke listener with state
  },
  listener: (context, state) {
    // do stuff here based on BlocA's state
  },
  buildWhen: (previous, current) {
    // return true/false to determine whether or not
    // to rebuild the widget with state
  },
  builder: (context, state) {
    // return widget here based on BlocA's state
  }
)

RepositoryProvider

RepositoryProvider는 RepositoryProvider.of(context)을 통해 Child에게 repository를 제공하는 위젯
하위 트리 내의 여러 위젯에 repository의 single instance를 제공할 수 있도록 DI Widget으로 사용 / bloc을 제공하려면 BlocProvider를 사용해야 하지만, RepositoryProvider는 Repository에 대해서만 사용!


RepositoryProvider(
  create: (context) => RepositoryA(),
  child: ChildA(),
);

// childA에서 다음을 사용하여 repository instance 검색할 수 있음

// with extensions
context.read<RepositoryA>();

// without extensions
RepositoryProvider.of<RepositoryA>(context)

MultiRepositoryProvider

MultiRepositoryProvider는 여러 Repository 위젯을 하나로 병합하는 위젯!


RepositoryProvider<RepositoryA>(
  create: (context) => RepositoryA(),
  child: RepositoryProvider<RepositoryB>(
    create: (context) => RepositoryB(),
    child: RepositoryProvider<RepositoryC>(
      create: (context) => RepositoryC(),
      child: ChildA(),
    )
  )
)

// to

MultiRepositoryProvider(
  providers: [
    RepositoryProvider<RepositoryA>(
      create: (context) => RepositoryA(),
    ),
    RepositoryProvider<RepositoryB>(
      create: (context) => RepositoryB(),
    ),
    RepositoryProvider<RepositoryC>(
      create: (context) => RepositoryC(),
    ),
  ],
  child: ChildA(),
)
profile
즐거움을 만드는 사람

0개의 댓글