[Flutter] GetX 사용하기

에딕·2021년 9월 25일
3

Flutter

목록 보기
2/5
post-thumbnail

📌 예시 코드


Flutter_GetX_Study_repo
GetX를 사용하기 위한 기초적인 내용을 담고있는 레포입니다.


📌 패키지 사용을 위한 작업


pubspec.yaml 파일에 패키지 추가

dependencies: get: ^4.1.4

설치

flutter pub get

import

import 'package:get/get.dart';


🔍 라우트(Route) 관리


  1. 라우트 관리를 위해 MaterialApp 를 GetMaterialApp로 변경
// 변경 전
MaterialApp(
  title: 'Getx example',
  home: HomePage(),
)
// 변경 후
GetMaterialApp(
  title: 'Getx example',
  home: HomePage(),
)

1.1 Navigation

1.1.1 Get.to()

새로운 화면으로 이동한다. 아래의 코드에서는 NextPage()로 이동한다.

Get.to(NextPage());

1.1.2. Get.toNamed()

미리 설정해둔 이름을 통해 새로운 화면으로 이동한다. 아래의 코드에서는 /next라는 이름을 가진 페이지로 이동

GetMaterialApp(
  title: 'Getx example',
  home: HomePage(),
  getPages: [
    GetPage(name: '/next', page: () => NextPage()),
  ],
)
Get.toNamed('/next');

1.1.3. Get.back()

이전 화면으로 돌아간다.

Get.back();

1.1.4. Get.off()

다음 화면으로 이동하면서 이전 화면을 아예 없애버린다. 이전 화면으로 돌아갈 필요가 없을 때 사용한다.

Get.off(NextPage());

NextPage()에서 버튼을 클릭해도 HomePage()가 없어졌기 때문에 돌아갈 수 없다.


1.1.5. Get.offAll()

***Get.off()가 이전 화면 하나만 없앴다면 Get.offAll()는 이전의 모든 화면을 없애고 다음 화면으로 이동한다.***

Get.offAll(NextPage());

1.2. Snackbar

기본적으로 Snackbar는 하단에서만 나온다. 그런데 GetX를 사용하면 Snackbar를 상단에 보이게 할 수도 있다.

1.2.1. Get.snackbar()

제목과 메시지를 설정하면 해당 내용으로 Snackbar를 보여준다. 지속시간(duration), 방향(snackPosition), 배경색(backgroundColor) 등 여러 설정들을 추가할 수 있다.

Get.snackbar('Snackbar', 'Snackbar', snackPosition: SnackPosition.TOP);

1.2.2. Get.showSnackbar()

***Get.snackbar()와 거의 동일하다. Get.showSnackbar()만의 특별한 용도가 있는지는 모르겠다.***

Get.showSnackbar(
  GetBar(
    title: 'Snackbar',
    message: 'Snackbar',
    duration: Duration(seconds: 2),
		snackPosition: SnackPosition.BOTTOM,
  ),
);

※ 기본 디자인임


1.3. Dialog

1.3.1. Get.defaultDialog()

Dialog를 화면에 띄어준다. 확인/취소 시에 실행할 함수(onConfirmonCancel), 확인/취소 텍스트(textConfirmtextCancel), 배경색(backgroundColor) 등 여러 설정들을 추가할 수 있다.

Get.defaultDialog(title: 'Dialog', middleText: 'Dialog');

제목과 텍스트만 설정했지만, 디자인 및 설정들이 기본적으로 되어있는 것을 볼 수 있다.


1.3.2. Get.dialog()

***Get.defaultDialog()와 달리 원래 사용하던 기존Dialog 위젯을 가져와서 사용할 수 있다.***

Get.dialog(
  Dialog(
    child: Container(
      height: 100,
      child: Center(
        child: Text('Dialog'),
      ),
    ),
  ),
);

1.4. BottomSheet

1.4.1. Get.bottomSheet()

내부에 들어갈 위젯만 넣어주면 해당 위젯을 포함하는 BottomSheet를 보여준다.

Get.bottomSheet(
  Container(
    height: 100,
    color: Colors.white,
    child: Center(
      child: Text('BottomSheet'),
    ),
  ),
)

🔍 2. 상태(State) 관리


GetX에는 크게 두가지의 상태 관리법이 존재한다.

2.1. simple 방식

첫번째 방식은 비교적 간단한(simple) 방식이다. 이 방식은 이후에 설명할 reactive 방식보다 메모리를 적게 사용한다는 장점이 있다.

2.1.1. 변수 선언

***GetxController를 extend하는 Controller 클래스를 선언하고, 초기값을 0으로 설정한 count1 변수를 선언한다.***

class Controller extends GetxController {
  var count1 = 0;
}

2.1.2. GetBuilder()

***GetBuilder을 통해 화면에 count1 변수를 보여준다. 이때 init을 설정하지 않으면 에러가 발생하는 것을 유의하자.***

GetBuilder<Controller>(
  init: Controller(),
  builder: (_) => Text(
    'clicks: ${_.count1}',
   ),
)

2.1.3. update()

이제 count1 변수를 증가시켜야 한다. 또한 증가할 때 이를 화면에 알려줘야한다. 이를 위해 update() 함수를 사용한다.

class Controller extends GetxController {
  var count1 = 0;

  void increment1() {
    count1++;
    update();
  }
}

Get.find(), Get.put()는 순서상 여기에 들어가는 것이 매끄러워서 넣은 것이지, simple 방식에 해당하는 것은 아니다. 두 방식(simple, reactive) 모두에서 사용된다.


2.1.4. Get.find()

Get.find()을 사용하여 increment1()을 호출하는 버튼을 만들어 텍스트 아래에 배치한다.

TextButton(onPressed: Get.find<Controller>().increment1, child: Text('increment1'))

하지만 리빌드해보면 Get.find<Controller>()에서 에러가 발생할 것이다.
이는 Get.find<Controller>()가 Controller를 찾는 시점이 GetBuilder()의 init에서 Controller를 등록하기 이전이라 그렇다.


2.1.5. Get.put()

이 문제를 해결하기 위해서 Get.put()을 사용한다.

우선 build() 메소드 내부에 controller 변수를 선언하며, 이때 Get.put()를 통해 Controller를 등록한다.


Widget build(BuildContext context) {
  final controller = Get.put(Controller());
  // ...
}

controller 변수를 선언하면서 Controller를 등록했기 때문에 GetBuilder에서 또 등록할 필요가 없다. 따라서 init 부분을 지운다.

GetBuilder<Controller>(
  // init 부분 삭제.
  builder: (_) => Text(
    'clicks: ${_.count1}',
  ),
)

버튼에서 increment1()를 호출할 때, Get.find() 대신 controller 변수를 사용한다.

TextButton(onPressed: controller.increment1, child: Text('increment1')),


2.2. reactive 방식

simple 방식은 메모리를 적게 사용한다는 장점이 있었다. 그렇다면 reactive 방식은 무슨 장점이 있고 어느 경우에 사용할까?

reactive 방식에는 simple 방식에는 없는 특별한 기능이 있다. 이에 대해선 reactive 방식에 대한 기본 설명 이후에 정리해보도록 하겠다.


2.2.1. Rx(observable 변수) 선언

reactive 방식에서는 observable 변수라는 특별한 변수를 사용한다. observable 변수를 Rx라고도 부른다. 이런 Rx를 선언하는 방법에는 아래와 같이 3가지가 있다.

  1. Value.obs
  2. Rx<Type>(Value)
  3. RxType(Value)

이 중 가장 간단한 1번 방법을 주로 사용한다.
우리도 1번 방법을 사용하여 count2 변수를 정의해보자.

  var count2 = 0.obs; // 1번
  var count2 = Rx<int>(0); // 2번
  var count2 = RxInt(0); // 3번

2.2.2. Rx(observable 변수)의 값 접근 .value

Rx의 값을 접근할 때는 일반적인 변수의 값의 경우와 다르게 .value를 통해 접근할 수 있다. 여기서 주의해야할 점이 있다. String과 int 같은 primitive type에는 .value를 사용해야하지만, List에서는 .value가 필요없다. dart api가 리스트에서만 .value 없이도 값에 접근할 수 있게 해주기 때문이다.

이 점은 좀 불편하다고 생각했다. .value를 붙이는 것은 더 길게 써야하는 것이고, 그 방법 마저도 List라는 예외가 존재하기 때문이다. 이 이유에 대해서 찾아보니, code generator와 decoration을 사용하면 이 불편함을 해결할 수 있지만, 외부 종속성을 없애고자 그대로 두었다고 한다.

void increment2() => count2.value++;

.value를 사용해서 count2의 값을 1 증가시키는 increment2() 함수를 정의했다. reactive 방식에선 update() 함수가 필요하지 않다.


2.2.3. GetX()

simple 방식의 GetBuilder과 같은 역할을 하는 것이 GetX이다. 그럼 GetX를 사용해서 count2의 값을 보여주는 텍스트를 만들어보자.

GetX<Controller>(
  builder: (_) => Text(
    'clicks: ${_.count2.value}',
  ),
),

Get.put(), init 부분 simple 방식과 똑같다.
필요한 경우에는 GetBuilder에서처럼 init을 통해 Controller를 등록할 수 있다.


2.2.4. Obx()

GetX보다 더 간단한 방법이 있다. 바로 Obx()를 사용하는 것이다. Obx()의 경우 사용할 컨트롤러의 종류를 따로 명시할 필요가 없고, 보여줄 위젯만 리턴하면 된다.
하지만 이 방법은 무조건 Get.put()을 필요로 한다.

Obx를 사용해서 count2의 값을 보여주는 텍스트를 만들어서 GetX를 통해 만든 텍스트 하단에 배치하자.

Obx(() {
  return Text(
    'clicks: ${controller.count2.value}',
  );
}),

이미 앞선 예시에서 Get.put()을 통해 선언한 controller가 존재하기 때문에 이를 바로 사용했다.


2.2.5. Workers

이전에 말했던 reactive 방식에서만 사용할 수 있는 특별한 기능들이 바로 Workers이다. Workers를 사용하면 Rx들의 변화를 감지하고 다양한 상황 별로 적절한 대응을 하도록 구현할 수 있다.

Workers에는 아래와 같이 총 4가지가 있다.

// count2가 처음으로 변경되었을 때만 호출된다.
once(count2, (_) {
  print('$_이 처음으로 변경되었습니다.');
});
// count2가 변경될 때마다 호출된다.
ever(count2, (_) {
  print('$_이 변경되었습니다.');
});
// count2가 변경되다가 마지막 변경 후, 1초간 변경이 없을 때 호출된다.
debounce(
  count2,
  (_) {
    print('$_가 마지막으로 변경된 이후, 1초간 변경이 없습니다.');
  },
  time: Duration(seconds: 1),
);
// count2가 변경되고 있는 동안, 1초마다 호출된다.
interval(
  count2,
  (_) {
    print('$_가 변경되는 중입니다.(1초마다 호출)');
  },
  time: Duration(seconds: 1),
);

이 4가지의 Workers를 Controller에 적용해보자.


void onInit() {
  super.onInit();

  once(count2, (_) {
    print('$_이 처음으로 변경되었습니다.');
  });
  ever(count2, (_) {
    print('$_이 변경되었습니다.');
  });
  debounce(
    count2,
    (_) {
      print('$_가 마지막으로 변경된 이후, 1초간 변경이 없습니다.');
    },
    time: Duration(seconds: 1),
  );
  interval(
    count2,
    (_) {
      print('$_가 변경되는 중입니다.(1초마다 호출)');
    },
    time: Duration(seconds: 1),
  );
}

Controller에 onInit() override하고, super.onInit()을 제일 먼저 호출한다. 그 다음 사용하고자 하는 Worker를 등록해주면 된다.


✨ References

https://terry1213.github.io/flutter/flutter-getx/#22-reactive-%EB%B0%A9%EC%8B%9D

  • 위의 글을 토대로 만들었으며 최소한의 내용만을 담으려고 글을 작성했습니다.
    좀 더 자세히 알고싶으신 분들은 위의 글을 참고해주시기 바랍니다!!

https://velog.io/@giyeon/flutter-2-1-Getx-%EB%8B%A8%EC%88%9C-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC#2-getview

  • GetView를 통한 코드 가독성 챙기기
profile
코딩💻 고양이😺

1개의 댓글

comment-user-thumbnail
2023년 4월 6일

엄청 정리가 잘 되어 있네요. 많은 도움이 되었습니다. 감사합니다.

답글 달기