[Flutter GetX : 02] 단순 상태 관리

728x90

단순 상태 관리

 

목차
1. 버튼, 페이지 구현
2. Controller 영역 구현
3. 위젯 단위로 분리하기
4. id값을 통한 독립적 상태 관리

1. 버튼, 페이지 구현

버튼을 누르면 카운트가 되는 간단한 예제를 GetX 방식으로 구현해보자.

(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/pages/home.dart)

import 'package:flutter/material.dart';
import 'package:flutter_getx/src/pages/simple_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 SimpleStateManagePage());
                },
                child: const Text("단순 상태 관리"),
            ),
          ]
        )
      )
    );
  }
}

(lib/src/pages/simple_state_manage_page.dart)

import 'package:flutter/material.dart';
import 'package:flutter_getx/src/pages/state/with_getx.dart';

class SimpleStateManagePage extends StatelessWidget {
  const SimpleStateManagePage({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 [
            Expanded(child: WithGetX(),),
          ]
        )
      )
    );
  }
}

 

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

import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Text("GetX", style: TextStyle(fontSize: 30)),
          const Text("0", style: TextStyle(fontSize: 50)),
          ElevatedButton(
              onPressed: () {},
              child: const Text("+"),
          )
        ],
      ),
    );
  }
}

 


2. Controller 영역 구현

update

이제 상태 관리를 관장하는 Controller 영역을 만들어 보자.

(lib/src/controller/count_controller_with_getx.dart)

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

class CountControllerWithGetx extends GetxController {
  int count = 0;
  void increase() {
    count++;
    update();
  }
}

increase 메서드가 호출되면 count를 증가시키고 update 메서드를 호출하여 위젯에 update 상황을 알린다.

 

put, find

이 getX controller를  contoller 부분에서 인스턴스로 선언해주면 어디서든 사용이 가능해진다.

provider 방식과 달리 getX는 context에 의존하지 않아서 Controller를 사용할 때만 선언하고 제거하기가 용이하다.

이러한 방식을 종속성 인스턴스 선언 방법이라고 하며, 총 4가지 방식이 제공된다.

 

 - Get.put()

 - Get.lazyPut()

 - Get.putAsync()

 - Get.create()

 

자세한 사항은 여기에!

https://afterdawncoding.tistory.com/233

 

[Flutter GetX : 04] 종속성 관리, 의존성 주입(put, lazyPut, putAsync, create)

종속성 관리, 의존성 주입(put, lazyPut, putAsync, create) 목차 1. Get.put() 2. Get.lazyPut() 3. Get.putAsync() 4. Get.create() provider 방식과 달리 getX는 context에 의존하지 않아서 Controller를 사용할 때만 선언하고 제거

afterdawncoding.tistory.com

 

simple_state_manage_page.dart로 돌아가서 put() 방식으로 인스턴스 선언을 해보자.

import 'package:flutter/material.dart';
import 'package:flutter_getx/src/controller/count_controller_with_getx.dart';
import 'package:flutter_getx/src/pages/state/with_getx.dart';
import 'package:get/get.dart';

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

  @override
  Widget build(BuildContext context) {
    Get.put(CountControllerWithGetx());  // getX controller를 인스턴스 선언 해주어야 어디서든 사용이 가능함.
    return Scaffold(appBar: AppBar(
      title: const Text("단순 상태 관리"),
    ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Expanded(child: WithGetX(),),
          ]
        )
      )
    );
  }
}

 with_getx.dart에서는 GetBuilder를 사용하여 Controller의 return 값을 받을 수 있다.

GetBuilder<타입>(
	builder: (controller) {
    return ...
    },
 ),

또한, Get.find 메서드를 사용해 Controller를 찾을 수 있다.

Get.find<타입>().increase(); -> 이렇게 하면 Controller 내부에 만들어 두었던 increase 메서드를 호출할 수 있게 된다.

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

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

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Text("GetX", style: TextStyle(fontSize: 30)),
          GetBuilder<CountControllerWithGetx>(
              builder: (controller) {
            return Text("${controller.count}",
                style: const TextStyle(fontSize: 50));
              },
          ),
          ElevatedButton(
              onPressed: () {
                Get.find<CountControllerWithGetx>().increase();
              },
              child: const Text("+"),
          )
        ],
      ),
    );
  }
}

버튼을 누르면 카운트가 올라가는 것을 확인할 수 있다.

참고로, 위에서 Get.put(CountControllerWithGetx());으로 Controller를 인스턴스 선언해주었는데 이 구문의 위치는 bulid 외부에 있더라도 정상적으로 실행된다. 위의 경우에는 simple_state_manage_page.dart(부모)에 선언했었지만 with_getx.dart(자식)에서 이를 바로 선언해도 아무런 문제가 없다는 것이다.  (선언이 자유롭기 때문이다.)

 

또한 다른 방법으로, 이 클래스가 생성될 때 바로 생성될 수 있도록 작성할 수도 있다.

simple_state_manage_page.dart에 있는 Get.put(CountControllerWithGetx());를 지우고 with_getx.dart에서 선언을 해보자.

(with_getx.dart)

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

class WithGetX extends StatelessWidget {
  WithGetX({Key? key}) : super(key: key);
  final CountControllerWithGetx _countControllerWithGetx = Get.put(CountControllerWithGetx());

  Widget _button() {
    return ElevatedButton(
      child: const Text("+", style: TextStyle(fontSize: 30)),
      onPressed: () {
        _countControllerWithGetx.increase();
      },
    );
  }
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Text("GetX", style: TextStyle(fontSize: 30)),
          GetBuilder<CountControllerWithGetx>(
              builder: (controller) {
            return Text("${controller.count}",
                style: const TextStyle(fontSize: 50));
              },
          ),
          _button(),
        ],
      ),
    );
  }
}
final CountControllerWithGetx _countControllerWithGetx = Get.put(CountControllerWithGetx());

클래스가 호출됨과 동시에 인스턴스가 생성되는 방식으로 Controller 인스턴스를 선언했다.

Widget _button() {
    return ElevatedButton(
      child: const Text("+", style: TextStyle(fontSize: 30)),
      onPressed: () {
        _countControllerWithGetx.increase();
      },
    );
  }

이전과 달리, find() 메서드를 사용할 필요없이 위에서 선언한 인스턴스를 바로 사용하면 increase 메서드를 찾을 수 있기 때문에 더욱 간결하게 코드를 작성할 수 있게 되었다.

 


3. 위젯 단위로 분리하기

provider와 비교했을 때, 이 방식의 장점은 상기했던대로 context에 의존하지 않게 되어 코드 작성이 간편해진다는 것뿐만 아니라function(위젯 단위로)으로 빼서 활용할 수 있다는 점!

 

따라서 이런 식으로도 코드를 작성할 수 있다.

Widget _button() {
	return ElevatedButton(
    	child: Text("+", style: TextStyle(fontSize: 30)),
        onPressed: () {
        	Get.find<CountControllerWithGetx>().increase();
        },
    );
}

with_getx.dart 코드에 적용하면 이렇다.

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

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

  Widget _button() {
    return ElevatedButton(
      child: const Text("+", style: TextStyle(fontSize: 30)),
      onPressed: () {
        Get.find<CountControllerWithGetx>().increase();
      },
    );
  }
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Text("GetX", style: TextStyle(fontSize: 30)),
          GetBuilder<CountControllerWithGetx>(
              builder: (controller) {
            return Text("${controller.count}",
                style: const TextStyle(fontSize: 50));
              },
          ),
          _button(),
        ],
      ),
    );
  }
}

 

 

provider 방식에서 이런 방식으로 코드를 작성하려면 StatefulWidget으로 바꿔주거나, StatelessWidget일 경우 _button() 메서드에 인수로 context를 넘겨줘야 한다. (context에 종속되기 때문..)

예를들어 이렇게 말이다.

Widget _button(context) {
	return ElevatedButton(
    	child: Text("+", style: TextStyle(fontSize: 30)),
        onPressed: () {
        	Provider.of<CountControllerWithGetx>(context, listen: false).increase();
        },
    );
}

따라서 getX방식이 개발자 입장에서는 작성과 활용이 상당히 간편해지는 것을 확인할 수 있다.

 

장점은 이뿐만이 아니다. 

 


4. id값을 통한 독립적 상태 관리

이런 상황에서, 위의 + 버튼은 위쪽 숫자를 카운트하고, 아래쪽 + 버튼은 아래 숫자를 카운트 할 수 있도록 만들고자 한다.

그러나 위에서 했던 방식으로는 무슨 버튼을 누르든간에 위, 아래 숫자가 동일하게 카운트되는 문제가 발생한다.

getX를 이용하면 특정 Controller에 id를 부여해서 특정 숫자만 카운트 할 수 있도록 간단하게 구현할 수 있다.

 

(with_getx.dart)

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

class WithGetX extends StatelessWidget {
  WithGetX({Key? key}) : super(key: key);
  final CountControllerWithGetx _countControllerWithGetx = Get.put(CountControllerWithGetx());

  Widget _button(String id) {
    return ElevatedButton(
      child: const Text("+", style: TextStyle(fontSize: 30)),
      onPressed: () {
        _countControllerWithGetx.increase(id);
      },
    );
  }
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Text("GetX", style: TextStyle(fontSize: 30)),
          GetBuilder<CountControllerWithGetx>(
            id: "first",
            builder: (controller) {
            return Text("${controller.count}",
                style: const TextStyle(fontSize: 50));
              },
          ),
          GetBuilder<CountControllerWithGetx>(
            id: "second",
            builder: (controller) {
              return Text("${controller.count}",
                  style: const TextStyle(fontSize: 50));
            },
          ),
          _button("first"),
          _button("second"),

        ],
      ),
    );
  }
}

(count_controller_with_getx.dart)

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

class CountControllerWithGetx extends GetxController {
  int count = 0;
  void increase(String id) {
    count++;
    update([id]);
  }
}

단순하게 버튼마다 독립적인 id값을 전달하고, 버튼이 눌릴 때 Controller에 id값을 전달하도록 한다.

이렇게 하면 여러 위젯들을 독립적으로 상태관리가 가능해진다.

 

728x90