단순 상태 관리 앱 화면

main(controller 등록)

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

  @override
  Widget build(BuildContext context) {
        // getx controller 등록
        Get.put(CountControllerWithGetX());
    return Scaffold(
        appBar: AppBar(
          title: Text('단순 상태 관리'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Expanded(child: WithGetX()),
              Expanded(
                                    // provider controller 등록
                  child: ChangeNotifierProvider<CountControllerWithProvider>(
                create: (_) => CountControllerWithProvider(),
                child: WithProvider(),
              )),
            ],
          ),
        ));
  }
}

Provider

controller

class CountControllerWithProvider extends ChangeNotifier {
  int count = 0;
  void increase() {
    count++;
    notifyListeners();
  }
}

ui

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

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        children: [
          Text(
            "Provider",
            style: TextStyle(fontSize: 50),
          ),
          Consumer<CountControllerWithProvider>(
            builder: (_, snapshot, child) {
              return Text("${snapshot.count}", style: TextStyle(fontSize: 50));
            },
          ),
          RaisedButton(
            onPressed: () {
              // listen: false를 줘서 consumer 부분만 rebuild
              Provider.of<CountControllerWithProvider>(context, listen: false)
                  .increase();
            },
            child: Text(
              "+",
              style: TextStyle(fontSize: 50),
            ),
          ),
        ],
      ),
    );
  }
}

GetX

controller

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

ui

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

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

비교

Provider는 consumer를 이용해 상태값을 가져오고 provider와 context를 이용해 controller의 비즈니스 로직을 불러옵니다.

GetX는 GetBuilder를 통해 상태값을 가져오고 Get.find를 통해 controller의 비즈니스 로직을 가져옵니다.

context를 사용하지 않는 GetX 방식은 위젯으로 분리하여 사용가능합니다.

...{
    ...
    return (
    ...,
    buildRaisedButton(),
    );

    Widget buildRaisedButton() {
      return RaisedButton(
        onPressed: () {
          Get.find<CountControllerWithGetX>().increase();
        },
        child: Text(
          "+",
          style: TextStyle(fontSize: 50),
        ),
      );
    }

}

반면, provider의 경우에는 stateful 위젯으로 변경하거나 context를 넘져워야합니다.

    buildRaisedButton(context),
            ],
          ),
        );
      }

  Widget buildRaisedButton(BuildContext context) {
    return RaisedButton(
          onPressed: () {
            // listen: false를 줘서 consumer 부분만 rebuild
            Provider.of<CountControllerWithProvider>(context, listen: false)
                .increase();
          },
          child: Text(
            "+",
            style: TextStyle(fontSize: 50),
          ),
        );
  }
}

GetX는 선언이 자유롭다.

부모에서 controller를 선언해줄 필요가 없습니다.

ui 부분에서 바로 사용 가능

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

  @override
  Widget build(BuildContext context) {
        // 바로 사용 가능
        Get.put(CountControllerWithGetX());
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text(
            "GetX",
            style: TextStyle(fontSize: 50),
          ),
          GetBuilder<CountControllerWithGetX>(builder: (controller) {
            return Text(
              "${controller.count}",
              style: TextStyle(fontSize: 50),
            );
          }),
          RaisedButton(
            onPressed: () {
              Get.find<CountControllerWithGetX>().increase();
            },
            child: Text(
              "+",
              style: TextStyle(fontSize: 50),
            ),
          ),
        ],
      ),
    );
  }
}

또한 클래스가 생성될때 바로 사용가능합니다.

class WithGetX extends StatelessWidget {
  const WithGetX({Key? key}) : super(key: key);
    // 클래스가 생성될때 바로 사용가능
    CountControllerWithGetX _countControllerWithGetX =Get.put(CountControllerWithGetX());
  @override
  Widget build(BuildContext context) {

    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text(
            "GetX",
            style: TextStyle(fontSize: 50),
          ),
          GetBuilder<CountControllerWithGetX>(builder: (controller) {
            return Text(
              "${controller.count}",
              style: TextStyle(fontSize: 50),
            );
          }),
          RaisedButton(
            onPressed: () {
                            //find를 할 필요가 없음
              _countControllerWithGetX.increase();
            },
            child: Text(
              "+",
              style: TextStyle(fontSize: 50),
            ),
          ),
        ],
      ),
    );
  }
}

특정 컨트롤러에 아이디를 부여해서 관리 가능

cotroller

class CountControllerWithGetX extends GetxController {
  int count = 0;
    // id를 받아서 update에 배열로 넣어줌
  void increase(String id) {
    count++;
    update([id]);
  }
}

ui

class WithGetX extends StatelessWidget {
  WithGetX({Key? key}) : super(key: key);
  CountControllerWithGetX _countControllerWithGetX =
      Get.put(CountControllerWithGetX());

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text(
            "GetX",
            style: TextStyle(fontSize: 50),
          ),
          GetBuilder<CountControllerWithGetX>(
                        // id 추가
            id: "first",
            builder: (controller) {
              return Text(
                "${controller.count}",
                style: TextStyle(fontSize: 50),
              );
            },
          ),
          GetBuilder<CountControllerWithGetX>(
            id: "second",
            builder: (controller) {
              return Text(
                "${controller.count}",
                style: TextStyle(fontSize: 50),
              );
            },
          ),
          buildRaisedButton("first"),
          buildRaisedButton("second"),
        ],
      ),
    );
  }

  Widget buildRaisedButton(String id) {
    return RaisedButton(
      onPressed: () {
                // id를 넘겨줌
        _countControllerWithGetX.increase(id);
      },
      child: Text(
        "+",
        style: TextStyle(fontSize: 50),
      ),
    );
  }
}

참고

https://www.youtube.com/watch?v=k3hgQu6it4c 

 

728x90

2021.06.16 - [Usage/Flutter] - [Flutter] Bloc Pattern (stateful -> bloc -> skip event bloc )

 

[Flutter] Bloc Pattern (stateful -> bloc -> skip event bloc )

BLOC Bussiness Logic Component 비즈니스 로직과 ui를 구분 짓고 필요에 따라 원하는 부분만 데이터 처리 실 사용 예제 버튼 클릭시 증감 1. Stateful version ui widget - 버튼 클릭시 증감 //stateless widge..

mugon-devlog.tistory.com

Install package

https://pub.dev/packages/provider

Project 구조

main.dart
src
 - count_home.dart 
 - count_provider.dart
 - count_home_widget.dart // statelesswidget

main.dart

void main() {
  runApp(MyApp());
    // runApp에서 provider를 불러오면 MyApp에서 접근 가능
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MultiProvider(
        providers: [
          ChangeNotifierProvider(
              create: (BuildContext context) => CounterProvider())
        ],
                // child의 모든 하위 요소들은 CounterProvider에 접근 가능
        child: Home(),
      ),
      // home: ChangeNotifierProvider(
      //   create: (BuildContext context) => CounterProvider(),
      //   child: Home(),
      // ),
    );
  }

count_provider.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

// ChangeNotifier 상속
// bloc 에서 stream 처리, sink 주입 했던 것을 처리해줌
class CounterProvider extends ChangeNotifier {
    // private
    // 이곳에서 선언되는 모든 변수는 상태관리 대상
  int _count = 0;
    // get 함수를 사용해서 private한 변수에 접근 가능하도록 만듦
  int get count => _count;
  add() {
    _count++;
        // 상태값이 update 되었다는 신호를 보내줌
    notifyListeners();
  }

  subtract() {
    _count--;
    notifyListeners();
  }
}

count_home.dart

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

  @override
  Widget build(BuildContext context) {
        // Provider.of로 사용할 provider를 가져옴
        // listen을 false로 해주면 현재의 widget은 rebuilding이 안됨
    CounterProvider countProvider =
        Provider.of<CounterProvider>(context, listen: false);
    return Scaffold(
      appBar: AppBar(
        title: Text("Provider"),
      ),
      body: CountView(),
      floatingActionButton: Row(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          IconButton(
            icon: Icon(Icons.add),
            onPressed: () => countProvider.add(),
          ),
          IconButton(
            icon: Icon(Icons.remove),
            onPressed: () => countProvider.subtract(),
          ),
        ],
      ),
    );
  }

count_home_widget.dart

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

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(
                // Provider.of를 통해 접근해서 count값 가져옴
                // build 전체를 rebuilding 함
        Provider.of<CounterProvider>(context).count.toString(),
      ),
    );
  }
}

// 특정 위젯만 rebuilding
class CountView extends StatelessWidget {
  const CountView({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
     return Center(
            // consumer를 사용해서 특정 위젯만 rebuilding
       child: Consumer<CounterProvider>(
                builder: (context, provider, child) {
         return Text(
           provider.count.toString(),
         );
       }),
    );
  }
}

참고

https://www.youtube.com/watch?v=AmmjdvhQG1s 

 

728x90

'Study > Flutter' 카테고리의 다른 글

[Flutter] Factory 패턴  (0) 2021.07.13
[Flutter] Stateful widget  (0) 2021.06.14
[UI초급] Container, materialApp, Scaffold  (0) 2021.06.07

+ Recent posts