목표:
왜 이거 써? 라는 물음에
“이게 좋아”, “남들이 그냥 좋다니 쓴다”
ㄴ> 라는 대답을 전하고 싶지 않기도 하지만
비교할 수 있는 대상이 있으면 이거 써보니 이게 문제였고 사용하고자 하는 라이브러리의 목적이 우리 프로젝트에는 어떻고 등등..
물음에대한 답 뿐만 아니라
개발에 대한 유연한 대처가 가능해질거라 믿는다자 그래서 RiverPod을 사용할 이유를 알기위해 flutter 3대 state라이브러리인 Getx를 탐구하고자 한다.
(riverPod을 사용할거니 Getx를 까보자는 마음으로 탐구해보았다.)
어떤 state관리 라이브러리가 좋을까 라는 주제엔 Getx 쉽고 좋아~ 라는 말을 너무 많이 봤다 그래서 flutter Get 공식 문서를 들어가보니
나온 내용을 해석해 볼때
뉴비인 내가 보기엔 모르지만 블로그를 검색하다보면 flutter 초창기엔 눈뜨고 코베이는 에러들이 많았던 것 같음
→ 패키지에 대한 불신 , 사라지지 않을까 하는 불안함으로 번짐
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()'),
) ,
InheritedWidget을 찾기 위해 컨텍스트가 필요한 경우 뷰 매개변수로 컨텍스트를 전달합니다. → 이게 보기 흉하다..?라고함
블록/저장소/컨트롤러 등의 클래스를 주입한다할 때 이걸 사용하지 않게 되면 하나하나 수동으로 없애줘야함( 라이브러리를 말하는 걸로 파악)
그러나 getx에서는 단순히 컨트롤러를 사용하고 더 이상 다른 사람이 사용하지 않을 때 단순히 메모리에서 삭제가 가능함.
실제로 코드를 작성해보면서 느낀점:
UI: snackbar , router , transition effect, dialog, bottomsheet ,theme GetConnect. . .
StateManage
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함,
자체적으로 초기화 가능
다양한 기능이 있어서 무거움
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),
),
),
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}',
),
),
1.단순 상태 관리 = simple StateManager
2.반응형 상태 관리 = reactive StateManager → 즉각적으로 반응해준다.
때문에 말 그대로
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();
}
별도의 라이프 사이클
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관계자도 탐탁치 않게 생각하는 것으로보면..
혼자 간단하게 구현하기엔 좋지만 프로젝트가 커질수록 관리하기가 힘들어 질 것 같다는 생각이다.