GetX

Updated:

GetX official page

GetX 특징

  • context 없이 routing 이 관리됩니다. Get.to(() => SomePage())

  • 일반적으로 dispose 관리를 해야합니다. getX 는 기본적으로 dispose 수행되고, 남기고 싶을때만 명시적으로 남기겠다는 코드를 넣습니다.

  • business logic 과 view 를 분리할 수 있습니다. (binding 이용)

GetX 사용

  • GetX package 를 설치하고, MaterialAppGetMaterialApp 으로 바꿔줘야 GetX 에 있는 기능들을 다 사용할 수 있습니다.

GetxController

  • controller 는 business logic 이 위치합니다. (데이터를 저장하고 가공하는 역활)

  • view 에서 이를 쉽게 가져다 쓸 수 있습니다.

  • dispose 를 따로 해주지 않아도 navigation stack 에서 빠질때 자동으로 dispose 됩니다.

  • onInit() : initState() 역활을 함

  • onReady() : widget 이 스크린에 다 그련진 후에 사용하는 method

  • onClose() : dispose() 역활을 함

// in controller.dart

class Controller extends GetxController {
  int counter = 0;

  void increment() {
    counter++;
    update(); // 상태가 변한것을 update 하는것
  }
}


GetBuilder

GetxController 의 저장된 data 를 view 단계에서 쓰이는 방식 중 하나임


GetBuilder<Controller>(
  init: Controller(), // app 의 어디서든 최초 1회만 호출하면 됨
  builder: (value) => Text(
    '${value.counter}'
  ),
),

GetBuilder<Controller> (
  builder: (value) => Text(
    '${value.counter}'
  ),
),
  • GetBuilder 는 stateFull widget 을 대신해서 사용할 수 있습니다.

  • 빠르고, 메모리 비용이 저렴합니다

  • unique id 를 줘서 구분 할 수 있습니다.


GetBuilder<Controller>(
  id: 'first', // getBuilder 를 id 로 구분함
  init: Controller(),
  builder: (value) => Text(
    '${value.counter}'
  ),
),

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

// in controller.dart

class Controller extends GetxController {
  int counter = 0;

  void increment() {
    counter++;
    update(['first']); // id 값을 parameter 로 설정하면 해당 id를 가진 getbuilder 만 update 됩니다
  }
}

  • 단점으로는 reactive 하지 않다는것임. (명시적으로 계속 갱신을 시켜줘야 작동한다는 것임) - 값이 변경 될때 마다, update() 을 호출해줘야 합니다

GetX

  • stream 방식으로 streamBuilder 와 비슷합니다

  • RxInt, RxString 등으로 변수를 사용합니다

  • 모든 class 객채도 사용 가능 합니다. myClass(). obs 형태로 선언

class Controller extends GetxController {
  RxInt counter = 0.obs;  // Rxint 타입으로 변수 선언 .obs 을 붙이면서 변수가 변화되는것을 감지하는 기능


  void increment() {
    counter.value++;
  }
}

GetX<Controller>(
  init: Controller(),
  builder: (val) => Text(
    '${val.counter.value}' // counter 의 변화를 바로바로 반영해야 되기 때문에 .value 라고 접근해야 됨
  ),
),

Obx

  • 사용 문법이 가장 단순

  • GetX 는 get.find 를 통해 사용하던 instance 를 찾아서 같이 공유해서 사용할 수 있습니다.

// model
class User {
  String? name;

  // constructure 생성
  User({this.name});
}

// Controller
class Controller extends GetxController {
  // instance 생성
  var user = User(name: "Jacob").obs; // 사용자 정의 User 클래스 생성

  // method (name chage)
  void chageName() => user.value.name = "Emma"; // value 로 접근해서 name 변수 변경
}


// View
Obx(() => Text( // Obx 로 감싸주면 끝, user 변화 catch 및 적용
  '${controller.user.value.name}'
  ),
),

// 다른 page에서 instance

class pageOne extends StatelessWidget {
  Controller controller = Get.put(Controller());
  // controller binding 필요함
}

// 다른 widget 에서 생성된 controller instance 그대로 가져다가 access 하기

class PageSeven extends StatelessWidget {
  Controller controller = Get.find(); // controller  접근하기
}

GetBuilder vs GetX, Obx 비교

  • GetBuilder : 가장 빠름, stream 사용안함, State를 builder 들간에 공유함. ram 절약 됨

  • GetX : value 가 실제로 바뀌었을때만 redraw 함. controller 를 instance 화 하지 않음. reactive 함

  • Obx : 문법이 제일 심플하고, 하나의 위젯에서 여러개의 controller 사용이 가능, binding 이 편함

Dependency injection

  • 하나의 instance 를 다른 instance 에 할당하는 방법을 말합니다
// 일반적인 dependency injection 예시

class HomePage extends StatelessWidget {
  Controller controller; // Controller type 의 변수를 생성
  HomePage({this.controller}); // contructor 생성

}

class OtherPage extends StatelessWidget {
  const OtherPage({Key? key}) : super(key: key);

  Controller someController = Controller(); // instance 생성

  @override
  Widget build(BuildContext context) {
    return Container(
        child: HomePage(
      controller: someController,
    ));
  }
}

  • GetX 에서는 Get.put 과 Get.find 를 이용합니다
class Homepage extends StatelessWidget {
  // Gex Controller instance 생성 Get.put 사용 (정의하기)
  Controller controller = Get.put(Controller());
}

class SecondPage extends StatelessWidget {
  Controller controller =
      Get.find(); // 기존에 생상된 controller instance 를 찾아서 가져와서 사용함 (가져오기)
}

Bindings

  • Bindings 를 상속하고, dependencies 를 override 합니다

  • Bindings 를 통해 View와 control 코드를 좀 더 분리해서 사용이 가능합니다

  • Bindings 는 dependencies 를 정의하고 이를 route 에 연결합니다

  • 이를 활용하기 위해서는 꼭 GetX route 시스템을 사용해야 합니다

  • controller 를 route 에 따라 관리 할 수 있기 때문에 편리 합니다. 페이지에 필요한 컨트롤러를 바인인하여 전달하면 페이지가 생성성되면서 바로 인스턴스가 선언되어 사용 가능한 상태가 되고 페이지에서 빠져 나오면 곧바로 해당 페이지에서 등록되어 사용되었던 인스턴스(controller) 가 자동으로 dispose 처리 됩니다

class HomeBiding implements Bindings {

  // extends: 부모에서 선언/정의를 모두 하며 자식은 메소드/변수를 그대로 사용할 수 있음
  // implements (interface 구현): 부모 객체는 선언만 하며 정의(내용)은 자식에서 오버라이딩 해야됨
  // abstract: extends 와 interface 혼합,  extends 하되 몇개는 추상 메소드로 구현되었음

  @override
  void dependencies() {
    // TODO: implement dependencies
    Get.put<Controller1>(Controller1());
    Get.put<Controller2>(Controller2());
  }
}


// 위의 정의된 dependency 를 route 에 binding
GetMaterialApp (
  initialRoute: "/",
  getpages: [
    GetPage(name: "/", page: () => HomePage(), binding: HomeBiding(),),
  ],
);


Get.to(HomeBiding(), binding: HomeBiding(),);
Get.toNamed("/", binding: HomeBindings(),);
GetMaterialApp (
  initialRoute: "/",
  // app 시작과 동시에 dependencies 를 만들 수 있다
  initialBinding: HomeBinding(),
);

GetMaterialApp (
  initialRoute: "/",
  // Bindings clsss 를 만들지 않고 바로 controller 를 binding 할 수 있다
  initialBinding: BindingsBuilder(() => {Get.put(Controller1())}),
);

class HomePage extends StatelessWidget {
  Controller1 controller = Get.find(); // Get.find() 를 통해 controller 를 view 에서 사용 가능함
}

Bindings 를 사용해야 되는 이유?

binding 을 사용하지 않아도 get.put 과 get.find 로 사용하면 되는데 만약 controller 가 10개 이상되고 그 이상 많게 되면 view 단계 page 에서 controller 를 매번 controller 개 만큼 find 해줘야 되서 코드가 길어지고 복잡해지는데 binding 을 통해 route 경로에 묶게 되면 clean code 가 됩니다

Get.put

  • controller 를 정의하는 명령어 임: view page 에서 instance 생성해서 controller 에 접근하는것입니다

  • Get.put 은 기본적으로 route 가 살아 있을 경우에만 memory 에 남아 있게 됩니다. 즉, 페이지에서 벗어나면 자동으로 dispose() 되는데, permanent: true 설정을하면 페이지를 벗어나도 instance 는 사라지지 않고 메모리에 남아 있게 됩니다

class HomePage extends StatelessWidget {
  // controller 정의 : controller instance 생성
  Controller controller = Get.put(Controller());

  @override
  Widget build(BuildContext context) {
    return Text(controller.name); // controller 에 저장되어 있는 data 표시
  }
}

class HomePage2 extends StatelessWidget {

  // tag 속성을 부여해서 같은 Controller 에서 각각 다른 변수로 사용 할 수 있음
  Controller controller1 = Get.put(Controller(), tag: 'ATag');
  Controller controller2 = Get.put(Controller(), tag: 'BTag');
  // permanent true 되면 페이지 벗어나도 instance 계속 남아 있게 됨
  Controller controller3 = Get.put(Controller(), tag: 'CTag', permanent: true);


  // ....
}

class SecondPage extends StatelessWidget {

  // get.find 에서 tag 로 각각 다른 객체를 불러 올 수 있음
  Controller controller1 = Get.find(tag: 'ATag');
  Controller controller2 = Get.find(tag: 'BTag');

  // ....
}

Get.lazyPut

  • 간단히 나중에 메모리에 올리겠다라는 명령어 인데, Binding 에서 선언할때 메모리로 올라 오는것이 아니라, get.find 로 호출 될때 get.put 이 그때 메모리에 올라가는것입니다

  • lazyPut 에 fenix: true 의 값을 주게 되면 다시 생성될때 re-initialize 됩니다

class HomeBiding implements Bindings {
  @override
  void dependencies() {
    // TODO: implement dependencies
    Get.lazyput<Controller>(() => Controller());
    Get.lazyput<Controller>(() => Controller(), tag: 'tagged!');
  }
}

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Text(Get.find<Controller>().name);
  }
}

Get.putAsync

  • 비동기 방식으로 put 을 사용한다는것인데, db 를 연결할때, http 를 불러오는것이 controller 안에 있을 경우 사용합니다. 먼저 요청을하고 비동기로 다른 작업을 먼저 처리 한다음에 get.find 되면 그때 get.put 하는것입니다

Get.create

  • Get.find 가 불릴때마다 instance 를 만듭니다. 즉, GetX 를 사용하는것은 생성된 instance 공유해서 를 get.find 로 찾아서 여러 페이지에서 사용하는 것인데, 만약, ListView.builder 같이 listView 를 만들때 return 값으로 Widget 을 looping 될때 Get.create 로 만들게되면 looping 할때 마다 controller instance 를 생성해서 각각의 변수를 만들어서 사용할 수 있습니다.

GetView

  • controller 를 조금더 편하게 만들수 있는 기능입니다. 만약 page 에 Controller getter 를 제공 합니다.

  • 하나의 Controller 만 사용한다면 GetView 가 좋은 옵션입니다. 왜냐하면 get.find 가 필요 없어도 data 값을 불러 옵니다. (get.find 가 필요가 없음)

class HomePage extends GetView<Controller> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Row(
        // get.find 없이도  GetView 안에서 자동으로 instance 가 생성되어 한개의 controller 를 가져올때 자동으로 controller 라는 변수에 접근해서 data 를 가져 옵니다
        children: [
          Obx(() => Text('controller.total.value')),
        ],
      ),
    ),
  }
}

GetWidget

  • GetView 와 비슷한데, 다른점은 controller 를 사용할때 get.find 가 자동 수행 됩니다 (최초 1회만) 그래서 get.create 과 같이 사용하면 좋습니다

Provider 와 같이 가장 많이 사용되는 상태관리 툴로써 GetX 는 크게 2가지 기능으로 나뉠 수 있습니다

  • Navigation

  • State Management

1.페이지 이동하기

ElevatedButton(
  onPressed: () {
    // 원래 material page 를 사용해야 함
    // Navigator.of(context).push(
    //   MaterialPageRoute(
    //     builder: (_) => ScreenTwo(),
    //   )
    // );

    // GetX를 사용해서 페이지 이동
    Get.to(() => ScreenTwo());
  },
  child: Text(
    "Screen 2 이동",
    style: TextStyle(fontSize: 20),
),

2.페이지 뒤로가기

ElevatedButton(
  onPressed: () {
    // 원래 뒤로 가기 기능 : pop 할때 뒤로갈 페이지가 있어야지 pop 을 하는데 안그려면 materialApp 을 완전히 나가버려서 black page 로 감
    // if(Navigator.of(context).canPop()){
    // Navigator.of(context).pop();
    // }

    // GetX 뒤로가기 : stack 을 하나 지우면서 pop 을 해야됨
    Get.back();
  },
  child: Text(
    '뒤로가기',
    style: TextStyle(fontSize: 20),
  ),
),

Kapture 2021-11-16 at 19 56 03

3.홈페이지로 바로가는 버튼

  • Get.off 을 사용하면 home 으로 바로 갈 수 있는 버튼 을 만드는것
ElevatedButton(
  onPressed: () {
    // 원래는 pushReplacement 사용해서 ScreenTwo() 로 넘어가면 뒤로가기 안되게 함
    // Navigator.of(context).pushReplacement(
    //   MaterialPageRoute(
    //     builder: (_) => ScreenTwo(),
    //   ),
    // );

    // Get.off 를 사용하면 쌓여 있는 stack 이 지워지면서 home 화면으로 감
    Get.off(() => ScreenTwo());
  },
  child: Text(
    "전 페이지로 돌아가지 못하게하기",
    style: TextStyle(fontSize: 20),
  ),
),

Kapture 2021-11-16 at 20 05 58

4.모든 페이지 스택 삭제하기

  • splash , login screen 을 만들 때, 어떠한 페이지를 띄우고서 바왔던 모든 page 들을 navigation stack 에서 삭제 시키는 것임
ElevatedButton(
  onPressed: () {
    // 모든 페이지를 삭제하고, 새로운 page 를 push 해주는것 pushAndRemoveUntil 을 사용하게 됨
    // Navigator.of(context).pushAndRemoveUntil(
    //   MaterialPageRoute(
    //     builder: (_) => ScreenTwo(),
    //   ),
    //   (route) => false,
    // );

    // Get.offAll 을 사용해서 뒤로가기 버튼을 눌러도 stack 이 다 지워지기 때문에 뒤로 갈수가 없게 됨
    Get.offAll(() => ScreenTwo());
  },
  child: Text(
    "모든 페이지 스택 삭제하기",
    style: TextStyle(fontSize: 20),
  ),
),

Kapture 2021-11-16 at 20 26 06

5.리턴값 받아오기

ScreenThree 에서 선택된 값 받아오기


// in navigation.dart

int returnVal = 0;

  Text(
    '리턴값 : $returnVal',
  ),
  ElevatedButton(
    onPressed: () async {
      // 받아온 값을 비동기로 resp 에 변수 선언함
      final resp = await Get.to(() => ScreenThree());
      // state 변경
      setState(() {
        returnVal = resp;
      });
    },
    child: Text(
      '리턴값 받아오기',
      style: TextStyle(fontSize: 20),
    ),
  ),

// in screen_three.dart
  int radioVal = 0;

  @override
  Widget build(BuildContext context) {
    return DefaultAppbarLayout(
      title: 'Screen Three',
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Column(
              children: [
                RadioListTile(
                  title: Text('0'),
                  groupValue: radioVal,
                  value: 0,
                  onChanged: (int? value) {
                    setState(() {
                      radioVal = value!;
                    });
                  },
                ),
                RadioListTile(
                  title: Text('1'),
                  groupValue: radioVal,
                  value: 1,
                  onChanged: (int? value) {
                    setState(() {
                      radioVal = value!;
                    });
                  },
                ),
                RadioListTile(
                  title: Text('2'),
                  groupValue: radioVal,
                  value: 2,
                  onChanged: (int? value) {
                    setState(() {
                      radioVal = value!;
                    });
                  },
                ),
              ],
            ),
            ElevatedButton(
              onPressed: () {
                // Get.back 하면서 result: radioVal 값을 전달 하기
                // 뒤로가기 기능
                Get.back(result: radioVal);
              },
              child: Text(
                '뒤로가기',
                style: TextStyle(fontSize: 20),
              ),
            ),
          ],
        ),
      ),
    );
  }

Kapture 2021-11-16 at 21 18 32

6.argument 값 보내기

위의 return 값을 받아오는 거와 반대로 정해진 argument 값도 다른 페이지에 전달할 수 있습니다 (Screen Four 로 보내기)

// in navigation.dart

ElevatedButton(
  onPressed: () {
    Get.to(() => ScreenFour(), arguments: 'GetX 값 보내기 test');
  },
  child: Text(
    'argument 보내기',
    style: TextStyle(fontSize: 20),
  ),
),

// in Screen four

child: Column(
  mainAxisAlignment: MainAxisAlignment.center,
  children: [
    Text(
      Get.arguments,
      style: TextStyle(fontSize: 20),
    ),
    ElevatedButton(
      onPressed: () {
        Get.back();
      },
      child: Text(
        '뒤로가기',
        style: TextStyle(fontSize: 20),
      ),
    ),
  ],
),

Kapture 2021-11-16 at 21 42 13

7.Transition

GetX 에서 제공하는 많은 page transition 을 적용하면 좀 더 다이나믹 하게 페이지 전환을 할 수 있습니다.

  • GetX 에서 제공하는 transition 속성은 다음과 같습니다
enum Transition {
  fade,
  fadeIn,
  rightToLeft,
  leftToRight,
  upToDown,
  downToUp,
  rightToLeftWithFade,
  leftToRightWithFade,
  zoom,
  topLevel,
  noTransition,
  cupertino,
  cupertinoDialog,
  size,
  native
}
ElevatedButton(
  onPressed: () {
    // GetX를 사용해서 페이지 이동
    Get.to(() => ScreenTwo(),
        transition: Transition.rightToLeftWithFade);
  },
  child: Text(
    "Transition",
    style: TextStyle(fontSize: 20),
  ),
),

Kapture 2021-11-16 at 22 01 44

8.Named Route

  • GetX 의 Navigation 에서 유용한 기능으로 Material App 에서 on generic route 를 사용해서 named route 를 사용 가능한데, GetX 에서는 getPages 를 사용해서 url 에 파라미터를 집어 넣는 기능을 간단히 만들 수 있습니다.

  • Web 에서 routing 할때, parameter 와 query 를 사용해서 자주 사용하는데 on generic routing 을 사용하게 되면 구현이 복잡하지만 GetX 에서는 간단히 사용할 수 있습니다.

// in main.dart

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter GetX',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
      getPages: [
        GetPage(
          name: '/nav',
          page: () => Navigation(),
        ),
        GetPage(
          name: '/two',
          page: () => ScreenTwo(),
        ),
        GetPage(
          name: '/three',
          page: () => ScreenThree(),
        ),
        GetPage(
          name: '/four',
          page: () => ScreenFour(),
        ),
        // named route 를 위한 :param 을 사용함
        GetPage(
          name: '/five/:param',
          page: () => ScreenFive(),
        ),
      ],
    );
  }
}

// navigation.dart

ElevatedButton(
  onPressed: () {
    // five/:param?id=444&name=Jacob 페이지로 named route 함
    Get.toNamed('/five/1234?id=444&name=Jacob');
  },
  child: Text(
    "Named route",
    style: TextStyle(fontSize: 20),
  ),
),

// screen_five.dart

child: Column(
  mainAxisAlignment: MainAxisAlignment.center,
  children: [
    Text(
      Get.parameters['param']!,
      style: TextStyle(fontSize: 20),
    ),
    Text(
      Get.parameters['id']!,
      style: TextStyle(fontSize: 20),
    ),
    Text(
      Get.parameters['name']!,
      style: TextStyle(fontSize: 20),
    ),
  ],
),

Kapture 2021-11-17 at 20 42 00

9.Snack bar 기능

  • material App 의 snack bar 의 기능을 GetX 에서 snack bar의 기능을 지원합니다
ElevatedButton(
  onPressed: () {
    Get.snackbar(
      '제목을 써주세요',
      '내용을 여기에 적으시면 됩니다',
      snackPosition: SnackPosition.BOTTOM,
    );
  },
  child: Text(
    "SnackBar",
    style: TextStyle(fontSize: 20),
  ),
),

Kapture 2021-11-17 at 20 53 09

10.Dialog 기능

  • GetX 를 사용하면 쉽게 다이얼 로그 (alert 창)을 쉽게 만들 수 있습니다. option 이 많기 때문에 customizing 을 쉽게 할 수 있습니다

ElevatedButton(
  onPressed: () {
    Get.defaultDialog(
      title: 'Dialog 제목',
      middleText: 'Dialog 내용',
    );
  },
  child: Text(
    "Dialog",
    style: TextStyle(fontSize: 20),
  ),
),

Kapture 2021-11-17 at 21 03 32

11.Bottom Sheet

  • 화면 하단에 listView 라던지 나타내고 싶은 Widget 을 넣으면 아래에서 부터 화면에 표시하기 됩니다
 ElevatedButton(
  onPressed: () {
    Get.bottomSheet(
      Container(
        color: Colors.white,
        child: Wrap(
          children: <Widget>[
            ListTile(
                leading: Icon(Icons.music_note),
                title: Text('Music'),
                onTap: () => {}),
            ListTile(
              leading: Icon(Icons.videocam),
              title: Text('Video'),
              onTap: () => {},
            ),
          ],
        ),
      ),
    );
  },
  child: Text(
    "Bottom Sheet",
    style: TextStyle(fontSize: 20),
  ),
),

Kapture 2021-11-17 at 21 21 58

State Management

1.on Update

  • 왠만한 상황에서는 on update 기능을 사용하는데, 왜냐하면 메모리 사용양이 적게 됨
// in getx_controller.dart

// Getx controller class 생성
class BuilderController extends GetxController {
  int count = 0;

  // increse method 생성
  increment() {
    count++;
    // state 가 변경될때 update() 호출해서 변경된것 알림
    update();
  }
}
// in on_update_screen.dart

class _OnUpdateScreenState extends State<OnUpdateScreen> {
  @override
  Widget build(BuildContext context) {
    // controller 변수에 Get.put 하면 initialize 해서 사용할 수 있음
    final controller = Get.put(BuilderController());

 child: Column(
  mainAxisAlignment: MainAxisAlignment.center,
  children: [
    Text(
      'On Update',
      style: TextStyle(
        fontSize: 20,
      ),
    ),
    GetBuilder<BuilderController>(
      builder: (_) {
        return Text(
          'count : ${_.count}',
          style: TextStyle(
            fontSize: 20,
          ),
        );
      },
    ),
    ElevatedButton(
      onPressed: () {
        controller.increment();
      },
      child: Text(
        'Count 업!',
        style: TextStyle(
          fontSize: 20,
        ),
      ),
    ),
  ],
),

Kapture 2021-11-18 at 14 26 20

2.Reactive

// in getx_controller.dart

class ReactiveController extends GetxController {
  // reactive 하게 변수 생성만들기
  RxInt count1 = 0.obs;
  var count2 = 0.obs;

class _ReactiveScreenState extends State<ReactiveScreen> {
  final controller = Get.put(ReactiveController());

child: Column(
  mainAxisAlignment: MainAxisAlignment.center,
  children: [
    Text(
      'Reactive',
      style: TextStyle(
        fontSize: 20,
      ),
    ),
    // Reactive 로 GetX 불러오기
    GetX<ReactiveController>(
      builder: (_) {
        return Text(
          'Count 1: ${_.count1.value}',
          style: TextStyle(
            fontSize: 20,
          ),
        );
      },
    ),
    ElevatedButton(
      onPressed: () {
        controller.count1++;
      },
      child: Text(
        'Count1 UP!',
        style: TextStyle(
          fontSize: 20,
        ),
      ),
    ),
  ],
),

Kapture 2021-11-18 at 14 43 35

Obx 을 사용

  • Obx 를 사용하면 builder 를 생성하지 않고 Controller 에 선언된 변수에 접근해서 사용할 수 있음 (Observable 의 값을 불러올때 사용함)
// reactive.dart

Obx(() {
  return Text(
    'Count 2 : ${controller.count2.value}',
    style: TextStyle(
      fontSize: 20,
    ),
  );
}),

Kapture 2021-11-18 at 14 49 57

  • obx 도 변경이 되는 것만 빌드가 됨
// in getx_controller.dart

  // observable 하는 값을 getter를 생성해서 obs 가 업데이트 될때 마다 getter 도 같이 업데이트가 됨
  get sum => count1.value + count2.value;
// getter 임으로 sum 뒤에 value 붙이지 않음
Obx(() {
  print("Sum BUILD");
  return Text(
    'Sum : ${controller.sum}',
    style: TextStyle(
      fontSize: 20,
    ),
  );
},),

Kapture 2021-11-18 at 14 57 51

class 의 instance 를 obx 로 만들기

// in getx_controller.dart

// User model 생성
class User {
  int id;
  String name;

  User({
    required int id,
    required String name,
  })  : this.id = id,
        this.name = name;
}

// model 로 부터 observable instance 생성
var user = User(id: 1, name: 'Jaocb').obs;

// observable instance 값 변경 하기
change({
  required int id,
  required String name,
}) {
  // .update 을 해줘야 observable instance 를 변경 해줄 수 있음
  user.update((val) {
    val!.id = id;
    val.name = name;
  });
}

// in reactive.dart

 Obx(() {
  return Text(
    'User : ${controller.user.value.id} / ${controller.user.value.name}',
    style: TextStyle(
      fontSize: 20,
    ),
  );
}),

ElevatedButton(
  onPressed: () {
    controller.change(id: 2, name: 'Emma');
  },
  child: Text(
    'Change User!',
    style: TextStyle(
      fontSize: 20,
    ),
  ),
),

Kapture 2021-11-18 at 15 11 44

  • 단, list 나 map 같이 primitive 값이 아닌 경우에는 .value 를 사용하지 않고 사용합니다
// in getx_controller.dart

List testList = [1, 2, 3, 4, 5].obs;
// in reactive.dart

 Obx(() {
  return Text(
    'List : ${controller.testList}',
    style: TextStyle(
      fontSize: 20,
    ),
  );
}),

image

Observable Worker 기능

  • worker 를 사용하지 않는 상황이면 되도록 on update 를 사용해서 state management 하는 것이 좋은데, 만약 아래와 같은 상황일때는 observable worker 를 사용해야 합니다

  • obs 을 사용할때는 주로 4가지 worker 를 사용할 때 쓰입니다

  • 주로 Debounce 를 유용하게 사용할 수 있는데 server 로 부터 fetch data 를 가지고 오는 상황에서 만약, user 가 form 에서 이 입력한 데이터를 서버로 보내서 검색한 후, Get 하는 상황에서 user 가 입력할때 마다 그 정보를 서버로 post, get 하는것보다 debounce worker 를 사용하게 되면 user 가 입력이 끝나면 그때 server 로 post 학게 될때 자주 사용됩니다

// getx_controller.dart

 @override
  void onInit() {
    super.onInit();

    // 4가지 worker : Ever, Once, Debounce, Interval
    //  Ever : value 값이 변경 될때 마다 실행
    ever(count1, (_) {
      print('EVER: Count1 이 변경 될때마다 실행');
    });
    // Once : value 값이 한번 실행 할때 만 실행되는 worker
    once(count1, (_) {
      print('ONCE: 처음으로 count1 이 변경 되었을때');
    });
    // Debounce: value 값이 변경 되고 지정된 time Duration 값이 지나고 나서 실행되는 worker (만약 Duration 시간 내에 value 변경이 일어나면 debounce 는 실행되지 않다가 Duration 시간이 지났는데 변경이 일어나지 않으면 그때 한번만 worker 실행함)
    debounce(
      count1,
      (_) {
        print("DEBOUNCE: 1초간 디바운스 한 뒤에 실행");
      },
      time: Duration(seconds: 1),
    );
    // Interval: value 값이 변경되는 runtime 시간 동안 inteval로 Duration 일정 시간 간격으로 실행되는 worker (반복되는 작업동안에 주기적으로 실행됨)
    interval(
      count1,
      (_) {
        print("INTERVAL: 1초간 인터벌이 지나면 실행");
      },
      time: Duration(seconds: 1),
    );
  }

image

🔶 🔷 📌 🔑

Reference

GetX pub.dev - https://pub.dev/packages/get

The Flutter GetX Ecosystem ~ Dependency Injection - https://medium.com/flutter-community/the-flutter-getx-ecosystem-dependency-injection-8e763d0ec6b9

Terry’s Dev-Diary - https://terry1213.github.io/flutter/flutter-getx/

코드 팩토리 - https://youtu.be/wgJItCEL7hkhttps://youtu.be/wgJItCEL7hk

Categories:

Updated:

Leave a comment