[Flutter GetX : 03] 반응형 상태 관리

728x90

반응형 상태 관리

 

목차
1. 버튼 카운트 예제
2. 이벤트 트리거
3. 다양한 자료형 선언과 변경 방법

반응형 상태 관리 방식의 장점

1. 값이 바뀌지 않는다면 굳이 update가 발생하지 않기 때문에 리소스 낭비를 줄일 수 있다는 것이다.

2. 이벤트를 트리거 할 수 있다.

 

대신 단순 상태 관리 방식에 비해 코드 구현이 다소 직관적이지 않을 수 있다.

 

1. 버튼 카운트 예제

(lib/main.dart)

import 'package:flutter/material.dart';
import 'package:flutter_getx/src/home.dart';
import 'package:get/get.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      initialRoute: "/",
      getPages: [
        GetPage(name: "/", page: () => const Home()),
      ],
    );
  }
}

(lib/src/home.dart)

import 'package:flutter/material.dart';
import 'package:flutter_getx/src/pages/reactive_state_manage_page.dart';
import 'package:get/get.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("라우트 관리 홈"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
                onPressed: () {
                  Get.to(const ReactiveStateManagePage());
                },
                child: const Text("반응형 상태 관리"),
            ),
          ]
        )
      )
    );
  }
}

(lib/src/pages/state/reactive_state_manage_page.dart)

import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {

    return Scaffold(appBar: AppBar(
      title: const Text("반응형 상태 관리"),
    ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text("GetX", style: TextStyle(fontSize: 30)),
            const Text("0", style: TextStyle(fontSize: 50)),
            ElevatedButton(
              child: const Text("+", style: TextStyle(fontSize: 30)),
              onPressed: () {},
            ),
          ]
        )
      )
    );
  }
}

controller도 구현해보자.

(lib/src/controller/count_controller_with_reactive.dart)

import 'package:get/get.dart';

class CountControllerWithReactive extends GetxController {
  RxInt count = 0.obs;  // 반응형으로 필드값을 관리할 수 있음.
  void increase() {
    count++;
  }
}

변수 선언 부분이 조금 특이한데, 저 부분만 고치면 provider의 changenotify나, getx 단순 상태 관리 방식에서 했던 update메서드 없이도 자체적으로 상태관리가 된다.

 

(reactive_state_manage_page.dart)

import 'package:flutter/material.dart';
import 'package:flutter_getx/src/controller/count_controller_with_reactive.dart';
import 'package:get/get.dart';

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

  @override
  Widget build(BuildContext context) {
    Get.put(CountControllerWithReactive());
    return Scaffold(appBar: AppBar(
      title: const Text("반응형 상태 관리"),
    ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text("GetX", style: TextStyle(fontSize: 30)),
            Obx(() => Text("${Get.find<CountControllerWithReactive>().count.value}",
                /* controller에서 선언한 obs의 변화를 감지했을 때 바로 Obx로 날려주는 기능을 함.
                다만 obs로 선언했던 값을 Obx로 넣어주지 않으면 에러가 발생하므로 반드시 넣어주도록 주의할 것.
                 */
                style: const TextStyle(fontSize: 50))),
            ElevatedButton(
              child: const Text("+", style: TextStyle(fontSize: 30)),
              onPressed: () {
                Get.find<CountControllerWithReactive>().increase();
              },
            ),
          ]
        )
      )
    );
  }
}
children: [
            const Text("GetX", style: TextStyle(fontSize: 30)),
            Obx(() => Text("${Get.find<CountControllerWithReactive>().count.value}",
                /* controller에서 선언한 obs의 변화를 감지했을 때 바로 Obx로 날려주는 기능을 함.
                다만 obs로 선언했던 값을 Obx로 넣어주지 않으면 에러가 발생하므로 반드시 넣어주도록 주의할 것.
                 */
                style: const TextStyle(fontSize: 50))),

controller 내부에 obs로 선언했던 count값을 Obx라는 키워드를 사용하여 받아온다.

설명대로, obs의 값이 변경되었을 때 Obx로 update값을 반영해주는 형태로 구성되어 있다. 

 

ElevatedButton(
              child: const Text("+", style: TextStyle(fontSize: 30)),
              onPressed: () {
                Get.find<CountControllerWithReactive>().increase();
              },

버튼이 눌리면 Controller내부의 increase메서드가 호출되도록 구현하면 된다.

(참고 : Obx 말고도 GetX를 사용하는 방법으로도 obs의 변화 값을 받아오는 방법이 있다.) 별 차이는 없다.

GetX(
	builder: (_) {
    	return Text(
        	"${Get.find<CountControllerWithReactive>().count.value}",
            style: TextStyle(fontSize: 50));
        },
    ),
    ...

 

reactive_state_manage_page.dart에서 count값을 5로 설정하는 버튼을 만들어 보자.

import 'package:flutter/material.dart';
import 'package:flutter_getx/src/controller/count_controller_with_reactive.dart';
import 'package:get/get.dart';

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

  @override
  Widget build(BuildContext context) {
    Get.put(CountControllerWithReactive());
    return Scaffold(appBar: AppBar(
      title: const Text("반응형 상태 관리"),
    ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text("GetX", style: TextStyle(fontSize: 30)),
            Obx(() => Text("${Get.find<CountControllerWithReactive>().count.value}",
                /* controller에서 선언한 obs의 변화를 감지했을 때 바로 Obx로 날려주는 기능을 함.
                다만 obs로 선언했던 값을 Obx로 넣어주지 않으면 에러가 발생하므로 반드시 넣어주도록 주의할 것.
                 */
                style: const TextStyle(fontSize: 50))),
            ElevatedButton(
              child: const Text("+", style: TextStyle(fontSize: 30)),
              onPressed: () {
                Get.find<CountControllerWithReactive>().increase();
              },
            ),
            ElevatedButton(
              child: const Text("5로 변경", style: TextStyle(fontSize: 30)),
              onPressed: () {
                Get.find<CountControllerWithReactive>().putNumber(5);
              },
            ),
          ]
        )
      )
    );
  }
}

 

count_controller_with_reactive.dart에서 putNumber 메서드를 구현한다.

import 'package:get/get.dart';

class CountControllerWithReactive extends GetxController {
  RxInt count = 0.obs;  // 반응형으로 필드값을 관리할 수 있음.
  void increase() {
    count++;
  }
  void putNumber(int value){
    count(value);
  }
}

5로 변경 버튼을 누르면 count값이 5로 설정된다.

같은 기능을 단순 상태 관리 방식으로 구현했다면 코드가 다음과 같을 것이다.

import 'package:get/get.dart';
import 'package:flutter/cupertino.dart';

class CountControllerWithGetx extends GetxController {
  ...
  void putNumber(int value){
    count = value;
    update();
  }
}

덜 직관적일 수 있으나, 어쨌거나 반응형 상태 관리 방식은 값이 바뀌지 않는다면 굳이 update가 발생하지 않기 때문에 리소스 낭비를 줄일 수 있다. 예를들어, 5로 변경 버튼을 여러번 누른다고 해도 count값이 5로 일정하기 때문에 계속해서 update가 일어나지 않는 것이다.

 

 

2. 이벤트 트리거

Getx Controller 라이프 사이클

-  기본 사이클은 onInit, onClose, onDelete 3가지이다.

onInit에 주로 쓰이는 것들에 대해서 살펴보자.

 

  • ever - 안에 값이 바뀔 때 마다 호출됨. (반응형 상태 관리 방식에서만 가능)
  • once - 딱 한번만 호출됨.
  • debounce - 최종적으로 값을 변경했을 때, 지정한 시간만큼의 텀이 지나면 호출됨.
    • (예: 버튼 쥰내게 다다다다 누르다가 멈추면 1초 뒤에 호출하기,
    • 검색 엔진에서 사용자가 키보드로 막 누르다가 잠시 멈췄을 때 서버로 필요한 데이터를 전송하는 방식)
  • interval - 변경이 계속 일어나고 있는 동안에 지정한 시간 텀마다 호출됨.
@override
    void onInit() {
    ever(count, (_) => print("매번 호출"));
    once(count, (_) => print("한번만 호출"));
    debounce(count, (_) => print("마지막 변경에 한번만 호출"), time: Duration(seconds: 1));
    interval(count, (_) => print("변경되고 있는 동안 1초마다 호출"), time: Duration(seconds: 1));
    super.onInit();
  }

 

3. 다양한 자료형 선언과 변경 방법

참고 : 반응형 상태 관리 방식에서는 RxInt 말고도 다양한 자료형을 다룰 수 있다. 다만 구현 방식이 조금 특이하므로 참고하면 좋을 것이다.

enum NUM { FIRST, SECOND }
class User{
  String? name;
  int? age;
  User({this.name, this.age});
}

class CountControllerWithReactive extends GetxController {
  // 반응형으로 필드값을 관리할 수 있음.
  RxInt count = 0.obs;  
  RxDouble _double = 0.0.obs;
  RxString strValue = "".obs;
  Rx<NUM> nums = NUM.FIRST.obs;
  Rx<User> user = User(name: "이순신", age: 25).obs;
  RxList list = [].obs;
  
  void changeValue() {	// 반응형 필드 값을 변경하는 방법
    count++;
    _double.value++;
    _double(444);
    nums(NUM.SECOND);
    user.update((_user){
      _user?.name = "이소룡";
    });
    list.add("가");
    list.addAll(); // 안에 list와 같은 Iterable 객체를 넣어준다.
    list.addIf(user.value.name == "이순신", "영웅"); // 앞에는 조건문을, 뒤에는 값을 넣어준다.
  }
}

 

728x90