ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Flutter / 플러터] BloC 패턴이 있는데 왜? Provider 를 써야 할까?
    개발일지/flutter 2021. 1. 8. 23:16

    안녕하세요 개발하는 남자입니다.

    오늘은 플러터 포스팅의 2번째 게시글입니다. 

    첫 번째 포스팅에서 다뤄보았던 Bloc 패턴을 알아봤습니다.

    혹시 Bloc 패턴에 대해 궁금하시다면? 아래 링크 클릭해서 보고 오시면 도움이 되실 것입니다. 

     

     

    Bloc 패턴이 무엇이고, 왜 사용하는 것일까?

    안녕하세요 개발하는 남자 개남입니다. 플러터 포스팅의 가장 첫 번째로 Bloc 패턴을 다루게 되었네요. 앞으로 플러터를 공부 및 정리를 하면서 포스팅을 추가해 나아가도록 할 계획입니다. 플러

    sudarlife.tistory.com

    지난번에도 언급했지만 앱을 만들면 UI와 비즈니스 로직을 분리해서 앱을 만들어야 하는데요.

    그것을 해결하기 위해 구글 개발자가 만든 Bloc패턴이 각광을 받았었습니다. 

    하지만 Bloc 패턴을 사용하기에 진입장벽이 높은것과, 불필요한 클래스를 여러 개를 만들어야 하는...

    즉 클레스가 다소 많아진다는 것이 불편하고 불만스러운 편이었습니다.

     

    그것을 해소시키기 위해 나온 것이 Provider입니다.

     

    Bloc 패턴과 Provider 사용과 사용목적은 같습니다. 

    상태 관리를 목적으로 하고 있으며 , UI와 비즈니스 로직을 분리하는 목적에서 

    동일합니다. 

     

    자 그럼 비교할 수 있는 것은 "어떻게" 가 될 것 같습니다.

    사용방법을 비교해보면서 어떤것이 개발자가 편하게 효과적으로 사용할 수 있을지만 알면 될 것 같습니다.


    필요 라이브러리 

    Bloc 

       - Pub.dev 에 Bloc , flutter_bloc 이라는 라이브러리를 사용해도 되지만 필수 사항은 아닙니다.

       - 아래 영상방법처럼 하면 라이브러리 사용하지 않고도 Bloc 패턴을 구현할 수 있습니다.

     

    Provider

       - pub.dev 에 provider라고 검색 혹은 아래 링크로 라이브러리를 사용해야 합니다.

     

    provider 4.3.2 | Flutter Package

    A wrapper around InheritedWidget to make them easier to use and more reusable.

    pub.dev

    pubspec.yaml 파일에 dependencies 하위로 넣어줍니다.

    dependencies:
      flutter:
        sdk: flutter
    
      cupertino_icons: ^0.1.3
      provider: ^4.3.2

    사용 선언

    Bloc

      - 전역 변수로 선언해서 사용 , 혹은 provider 랑 연계해서 사용하기도 한다.

     

    Provider

      - Provider를 사용을 선언한 순간 그 Provider에 속한 child 자녀들은 모두 Provider 에 접근이 가능하다.

      - Provider 선언한 위치에서 그 상위 Widget에서 provider에 접근할 수 없다 

     

    < 하나의 Provider 사용을 위한 선언 >

    MaterialApp(
          title: 'Flutter Demo',
          home: ChangeNotifierProvider(
            create: (BuildContext context) => CounterProvider(),
            child: Home(),
          ),
        );

    < 다중 Provider 사용을 위한 선언 >

    MaterialApp(
          title: 'Flutter Demo',
          home:  MultiProvider(
            providers: [
              ChangeNotifierProvider(
                  create: (BuildContext context) => CounterProvider())
            ],
            child: Home(),
          ),
        );

    상태 변경

    Bloc

       - Stream을 만들어주고 Sink를 더함으로 상태를 변경한다.

    class CountBloc {
      int _count = 0; // 상태
      final StreamController<int> _countSubject = StreamController<int>.broadcast(); // Stream 생성
      Stream<int> get count => _countSubject.stream; // 구독자들에게 변경 사항 전송
    
      add() {
        _count++;
        _countSubject.sink.add(_count); // 이벤트를 받아 stream에 상태 변경 추가
      }
    }

    Provider

      - ChangeNotifier 상속받아 notifyListeners() 상태 변경 사항을 알림.

    class CounterProvider extends ChangeNotifier {
      int _count = 0; // 상태
      add() {
        _count++; //상태 변경
        notifyListeners(); // 상태 변경 된 것을 알림
      }
    }
    

     

    이미 상태 변경 방법만 봐도 간결해 짐을 볼 수 있다.

    심지어 Bloc 패턴을 정석으로 사용하면 Event Stream 도 생성하고 Event Type 클래스도 만들어야 하고 할 것이 많다. 

    하지만 Provider는 상태 관리를 직접 하지 않고 ChangeNotifier에게 넘겨주기만 하면 알아서 된다.


    UI 상태 받아 처리하기

    Bloc

      - StreamBuilder 위젯을 사용하여 상태를 받을 수 있다.

    return Center(
          child: StreamBuilder(
            stream: countBloc.count,
            initialData: 0,
            builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
              if (snapshot.hasData) {
                return Text(snapshot.data.toString());
              }
              return CircularProgressIndicator();
            },
          ),
        );

     

     

     

    Provider

      - Provider.of 를 사용해서 CounterProvider로 직접 접근을 할 수 있으며 상태를 받아와 업데이트가 가능하다.

      - 두 번째는 Consumer를 활용해서 provider에 접근하여 데이터를 받아올 수 있다 

      - 두 개는 목적에 따라 활용해야 한다. 

    return Center(
          child: Text(
            Provider.of<CounterProvider>(context).count.toString(),
          ),
        );
    return Center(
          child: Consumer<CounterProvider>(builder: (context, provider, child) {
            return Text(
              provider.count.toString(),
            );
          }),
        );

    직접 접근해서 받아오는 경우 현 위젯 전체가 리로드 되는 현상이 발생된다. 

    가벼운 위젯일 경우 바로 사용해도 무방하다.

     

    두 번째 Consumer를 활용하는 경우 builder 부분만 호출되기 때문에 현 위젯이 리로드 되지 않는다

    여러 효과나 연산이 많이 있는 위젯일 경우는 Consumer를 사용하는 것이 좋을 것으로 보인다.

     

    위 내용을 아래  영상에서 볼 수 있습니다 :)

     

     


    아주 간단하게 Provider에 대해서 알아보았습니다.

    Bloc과 동일한 기능을 하지만 사용 측면에서 Provider 가 너무 간편하고 효과적이고 직관적이기에 Provider는 필수라고 생각합니다.

     

    댓글

Designed by Tistory.