[Flutter] Getx란?

fanthasium·2023년 9월 17일
1

목표:

알고는 쓰자

🧐 Why (?)

왜 이거 써? 라는 물음에

“이게 좋아”, “남들이 그냥 좋다니 쓴다”

ㄴ> 라는 대답을 전하고 싶지 않기도 하지만

비교할 수 있는 대상이 있으면 이거 써보니 이게 문제였고 사용하고자 하는 라이브러리의 목적이 우리 프로젝트에는 어떻고 등등..

물음에대한 답 뿐만 아니라

개발에 대한 유연한 대처가 가능해질거라 믿는다

자 그래서 RiverPod을 사용할 이유를 알기위해 flutter 3대 state라이브러리인 Getx를 탐구하고자 한다.

(riverPod을 사용할거니 Getx를 까보자는 마음으로 탐구해보았다.)

🤔Getx가 뭔데?

어떤 state관리 라이브러리가 좋을까 라는 주제엔 Getx 쉽고 좋아~ 라는 말을 너무 많이 봤다 그래서 flutter Get 공식 문서를 들어가보니

구구절절 하나하나 맞는 말로 포장즁

나온 내용을 해석해 볼때

  1. 뉴비인 내가 보기엔 모르지만 블로그를 검색하다보면 flutter 초창기엔 눈뜨고 코베이는 에러들이 많았던 것 같음
    → 패키지에 대한 불신 , 사라지지 않을까 하는 불안함으로 번짐

  2. flutter 보일러플레이트..넘 마나

    //로 보내서
    Navigator.pushNamed(context, '/B', arguments: "Hello");
    
    //로 받기
    String? tmp = ModalRoute.of(context)?.settings.arguments.toString();
            tmp.tittle
    
    getx에선
    
    GetMaterialApp(
          title: 'GetX Example',
          home: FirstScreen(),
          getPages: [
            GetPage(name: '/second/:uid', page: () => const SecondScreen(),transition: Transition.downToUp),
            //Route 사용을 위한 NextPage 이름 설정
          ],
        );
    TextButton(
                    onPressed: () => Get.toNamed('/second/28353',arguments: "toNamed()로 보냈심둥"), // 미리 설정해둔 이름을 통해 새로운 화면으로 이동
                    child: const Text('Get.toNamed()'),
            ) ,
    
  3. InheritedWidget을 찾기 위해 컨텍스트가 필요한 경우 뷰 매개변수로 컨텍스트를 전달합니다. → 이게 보기 흉하다..?라고함

  4. 블록/저장소/컨트롤러 등의 클래스를 주입한다할 때 이걸 사용하지 않게 되면 하나하나 수동으로 없애줘야함( 라이브러리를 말하는 걸로 파악)
    그러나 getx에서는 단순히 컨트롤러를 사용하고 더 이상 다른 사람이 사용하지 않을 때 단순히 메모리에서 삭제가 가능함.

실제로 코드를 작성해보면서 느낀점:

이게되네?.. 하는 것들이 참 많았다.

UI: snackbar , router , transition effect, dialog, bottomsheet ,theme GetConnect. . .

StateManage

  • Obx, GetX, GetBuilder

1. obx:

observable의 observable의 변화를 listen함 ,
controller인스턴스가 다른곳에서 미리 초기화 돼 있어야함

- 사용 문법이 가장 단순
- controller의 이름을 지을 수 없어서 별도로 사용할 땐
Get.find<Controller>.[함수명]으로 사용
class Controller extends GetxController{
final person = Person().obs; //observable의 변화를 listen함 

}

final Controller controller = Get.put(Controller()); 

 Obx(
  () => Text(
    'Age: ${controller.person().age}',      //이렇게 간접참조로 받아오거나
    style: TextStyle(fontSize: 20, color: Colors.white),
  ),
),

2. GetX:
observable의 변화를 listen함,
자체적으로 초기화 가능
다양한 기능이 있어서 무거움

  • stream 방식이다. StreamBuilder와 비슷
  • RxInt, RxString 등으로 변수 사용가능
  • Controller를 정해줄 수 있음
GetX<Controller>(
  builder: (_) => Text(
    'Name: ${controller.person().name}',
    style: TextStyle(fontSize: 20, color: Colors.white),
  ),
)),

//or 
 GetX(
   init: Controller(),
   builder: (controller) => Text(
     'Age: ${Get.find<Controller>().person().age}',  
      style: TextStyle(fontSize: 20, color: Colors.white),
    ),
  ),

3. GetBuilder:

  • observable의 변화를 listen 안 함

  • 수동으로 UI 리빌드 해야해서 반드시 update 매서드 호출, 자체적 초기화 가능

  • 빠르고, 메모리 비용이 저렴하지만 reactive 하지 않다.

class Controller extends GetxController {
  int counter = 0;

  void increment() {
    counter++;
    update(); // -> 변화를 notifty 한다.
  }
}
GetBuilder<Controller>(
  init: Controller(), // => app의 어디서든 최초 1회만 호출 하면 된다.
  builder: (value) => Text(
    '${value.counter}',
  ),
),

GetBuilder<Controller>(
  builder: (value) => Text(
    '${value.counter}',
  ),
),

GetX를 통한 상태관리 방식은 크게 두가지

1.단순 상태 관리 = simple StateManager

2.반응형 상태 관리 = reactive StateManager → 즉각적으로 반응해준다.

때문에 말 그대로

  • 반응형 상태 관리의 경우 데이터 변화가 있을 때만 재랜더링을 하게 됨
  • 단순 상태 관리는 기존의 데이터와 변경되는 데이터가 같은지 확인하지 않는다

반응형 상태관리 worker:

 
  void onInit() {
    once(counter, (_) {
      print('once : $_이 처음으로 변경되었습니다.');
    });
    ever(counter, (_) {
      print('ever : $_이 변경되었습니다.');
    });
    debounce(
      counter,
          (_) {
        print('debounce : $_가 마지막으로 변경된 이후, 1초간 변경이 없습니다.');
      },
      time: Duration(seconds: 1),
    );
    interval(
      counter,
          (_) {
        print('interval $_가 변경되는 중입니다.(1초마다 호출)');
      },
      time: Duration(seconds: 1),
    );
    super.onInit();
  }
  • ver : 매번 변경 될 때 실행
  • Once : 처음 변경 되었을 때만 실행
  • Interval : 계속 변경이 있는 동안 특정 지정 시간 인터벌이 지나면 실행
  • Debounce : 인터벌이 끝나고 나서 특정 지정 시간 이후에 한번만 실행

별도의 라이프 사이클

  • onInit - GetxController 가 생성될 때 호출
  • onReady - GetxController 가 initialized 된 후 호출
  • onClose - GetxController 가 메모리에서 제거될 때 호출

Getx라는 하나의 세계관에 들어간 느낌

이렇게 하다보면 단점이.. 어디에 있나 싶다. ( 너무 완벽해)

짧게짧게 구조화 하면 뭔가를 만들때는 느껴보지 못했는데

네이버 라인의 분석을 보니

“그렇네?!”
하는 생각도 들었다

그래서~

GetX 단점..

나의 생각 : 단점은 위에서 말한 Getx라는 하나의 세계관에 들어간 느낌 이라는 것
Flutter를 하고 있는지 Getx를 하고 있는지 모르겠다.

              (개인 프로젝트로 그냥 뭔가를 하기엔 정말 좋음)
              
              
              ### `BuildContext` 의 개념이 중요하다 ###
  • BuildContext는 Flutter 위젯이 작동하는 주요 개념 중 하나 Flutter와 같은 선언형 UI 방식 개발에서는 화면을 그리기 위해 위젯 트리 최상단에서부터 자식들을 하나씩 그려나가는데, 각 위젯이 화면에 그려질 때 이BuildContext를 전달받는다.
    BuildContext는 위젯 트리에서 현재 그려야 할 위젯의 위치를 나타내고

1. 생명 주기 관리
2. 의존성 주입
3. 의존성 변경

을 가능케 하는데!!

GetX는 BuildContext를 통한 참조 방식이 아니기에 예기치 못한 오류가 생김

final tab1 = TabViewModel('tab1');
Get.put(tab1)

final tab2 = TabViewModel('tab2'); // 동일한 클래스로 다른 인스턴스를 생성
Get.put(tab2)

// tab1을 받을지 tab2를 받을지 알 수 없음
TabViewModel tab = Get.find()

...

// 이 문제는 GetX에서 태그를 지정하는 방식을 사용해야 해결할 수 있음

// 태그 지정해야 함
Get.put(TabViewModel(), tag: 'tab1');
Get.put(TabViewModel(), tag: 'tab2');

// 뷰모델 사용, 태그를 알아야 가져올 수 있음
TabViewModel tab1 = Get.find(tag: 'tab1');
TabViewModel tab2 = Get.find(tag: 'tab2');
// ← 뷰모델을 사용하는 자식 위젯에게 태그 값을 매번 전달해야 해서 불편, BuildContext를 사용하는 게 낫지 않을까?
// GetX - 현재 메모리에 존재하는 동일한 타입의 객체 리턴
ListViewModel obj = Get.find();

// Provider - 항상 BuildContext를 파라미터로 전달받아야 함
ListViewModel obj = context.read();

위 내용이 Getx치명적인 단점? 이라고 볼수 있을 지도

Getx는 flutter 사이클이 아닌 스스로의 인스턴스를 만들어 별도의 Getx만의 사이클을 만든다.

해당 코드를 보니:

저렇게 태그해서 어디서 참조 받는지 사용하고 관리 해줄거면 buildcontext로 내가 사용하는 부모의 context를 따라가는게.. 더 낫지..?

( 역시 네이버인가.. 싶은 분석 👍 )

### 끝으로

보다보니 앱개발자면서 native보단 flutter를 더 의존하게..되고 도구에 의존하면서좋은게 좋은거지..라고 생각한걸 좀 반성하게 되는데

riverpod, google관계자도 탐탁치 않게 생각하는 것으로보면..
혼자 간단하게 구현하기엔 좋지만 프로젝트가 커질수록 관리하기가 힘들어 질 것 같다는 생각이다.

profile
디그다 디그다 (끙챠끙챠)

0개의 댓글