ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • bloc 패턴 - flutter_bloc 패키지 사용
    flutter 2021. 7. 16. 23:33

     

    ** flutter_bloc: ^7.0.0 기준으로 작성됨.

     

    bloc패턴을 정석적으로 구현하려면 코드가 다소 방대해지기 때문에, rxdart의 스트림을 활용하여 구현하는 경우가 있습니다.

    class를 생성하여 bloc으로 정의하고,

    내부 로직은 rxdart를 사용하여 상태를 변경할때마다 생성된 인스턴스에서 그클래스로 event를 던지고, 이 이벤트를 listen하여 각각 함수로 분기하여 sink 에 add 하는 방식으로 구현할 수 있습니다.

    이렇게 하고 sink의 최신값을 지속적으로 갱신할 수 있습니다.

     

    클라이언트 view 단에서는 해당 클래스의 BehaviorSubject의 stream 을 StreamBuilder를 구현하여 

    StreamBuilder의 상태가 바뀔때마다 실시간으로 변경되는 데이터나 UI를 구현할 수 있습니다.

     

    하지만 이방법은 간단한 페이지를 만들때는 유용하지만

    여러 위젯이 복합적으로 상태를 관리해야 되는 상황에서는 다소 최적화하기 어렵습니다.

     

    때문에 다소 기능이 많거나 복합적인 Ui의 페이지를 구현할때는 flutter_bloc패키지를 사용해
    정석적인  bloc 패턴을 구현하는 게 좋습니다.

     
    flutter_bloc로 블록패턴을 구현하게되면

     

    BlocProvider(create: (_) =>PostBloc(),
    child: PostView())

     

    이런식으로 Bloc을 사용할 위젯에 Bloc을 주입을 합니다.

    (BlocBrovider가 Bloc을 생성해주고, 이 생성된 인스턴스에 접근해서 이벤트를 던지거나 상태를 변경하려면, BlocProvider.of<PostBloc>(context) 로 접근하면 됩니다.

    BlocProvider로 Bloc을 주입하면  주입받은 위젯에서는 항상 동일한 bloc 인스턴스에

    접근할 수 있게 됩니다.

     

    final mainBloc= BlocProvider.of(context);

    mainBloc.add(이벤트클래스(이벤트클래스내부에 정의된 기타등등..)); 이런식으로

    이벤트를 던지면 PostBloc클래스의 mapEventToState 함수로 이벤트가 던져지고 이곳에서 이벤트에

    따른 비즈니스 로직을 핸들링 할 수 있습니다.

     

    @override
    Stream<PostState> mapEventToState( PostEvent event) async* {

      if (event is getCurrent) {
    final result = await getCurrentPost();     //getCurrentPost를 통해 초기 post 데이터를 가져옴,,,
    yield PostCurrent(result);
    }

    }

     

    이런식으로 mapEventToState 가 이벤트를 핸들링하고, PostState타입의 Stream 을 리턴합니다.

    event 로만 분기할 수 있는게 아니라 state에 따른 분기도 가능합니다.

     

     

    Bloc패턴을 구현하려면 기본적으로

    메인이되는 Bloc클래스,

    상태클래스, 이벤트 클래스 이렇게 세가지가 필요 합니다.

     

    메인블록은

    class PostBloc extends Bloc<PostEvent, PostState>  이런식으로 이벤트클래스와 상태 클래스를 상속합니다.

     

    mapEventToState 에서 분기된 이벤트가 특정 상태값(UI에 갱신될 최근 데이터값)을 상태클래스에 요청하고,

    최종적으로 갱신된 상태값을 Stream으로 리턴합니다. 

     

    BlocProvider에서 Bloc 주입 ->

     

      if (UI단에서 사용자의 이벤트가 발생하면)

    뷰단에서 BlocProvider.of(context)로 이벤트를 add ->

    Bloc클래스에서 이벤트 핸들링 ->

    (이벤트 클래스는 거진 mapEventToState  에 던져주는 용도로만 사용) ->

    BlocState를 가져와서 최종적으로 UI단에 Stream으로 리턴

     

    -> BlocBuilder에서 자동적으로 UI가 갱신됨.(상태가 바뀌면 알아서 갱신됩니다.)

    혹은 상태에 따라 로직을 수행할 수도 있습니다.

     

     

    이러한 구조라고 생각하면됩니다.

     

    주의할 점은 Bloc을 사용할땐 setState함수를 왠만하면 안쓰는게 좋습니다.

    BlocBuilder가 하위로 들어있는 메인 위젯에서 어느 특정 부분에서 위젯을 갱신하려고 (예를들면 dropdown 사용과같은 간단한 UI를 변경해주기위해..) 버튼 클릭후 setState를 실행한다거나 하면..

     

    @override 하고 있는 Widget build함수를 실행하게되어 전체 scaffold나 container가 재 빌드되서 초기화 될수가 있습니다.

    내부적으로 존재하는 BlocBuilder도 초기화가 되어 state나 event가 초기화 될 수 있습니다.

     

    setState를 실행할때 특정 위젯이 초기화 되지 않기 위한 방법이 찾아보면 또 있겠지만..

    왠만하면 BlocLisnter나 BlocBuilder로 갱신해주는게 좋아보입니다.

     

     

     

     

     

     

     

     

     

Designed by Tistory.