티스토리 뷰

카테고리 없음

[Flutter] State 관리(1)-Provider

필명을...뭐로해.. 2022. 3. 31. 01:23

Flutter에서 전역 상태를 관리하거나 위젯간에 상태를 공유하기위하 사용함.

widget간 데이터 공유가 가능하기는 하지만 한가지 상태 변화로 인해 트리 구조에서 state가 전달되기 때문에 불필요한 위젯들이 Rebuild 되면서 성능이슈가 나타나고 이를 provider가 해결해준다.

              <기존 구조>                                                                                                     <Provider 적용 후 구조>

1. Provider 특징

  • 코드 역할별(UI, API 요청, 모델 관리 등)로 클래스를 나눌 수 있음
  • 데이터 공유 eg. 인증정보, 장바구니정도 등 앱 전반에서 사용 될 데이터 공유
  • 좀 더 간단한 코드(bloc과 비교했을 때,,)

2. Provider 사용하기

기본적인 Provider 사용법 - 데이터의 생산과 소비

Provider<int>.value( // int 타입 데이터 생산
      value: 5,
      child: Container(),
)

var data = Provider.of<int>(context) // 데이터 소비

ChangeNotifier 사용 하기 - 변경되는 값

provider 를 사용하기 위해서는 changeNotifier를 사용해서 Count 클래스(모델..?)를 생성함.

import 'package:flutter/material.dart';

class Counts with ChangeNotifier {
  int _count = 0;
  int get count => _count; // private 변수에 접근 가능한 getter 생성

  void add() {
    _count++;
    notifyListeners(); // 이 함수를 무조건 실행해 줘야 다른 위젯들에서 해당값이 변경된지 알 수 있다.
  }

  void remove() {
    _count--;
    notifyListeners();
  }
}

Counter 위젯 생성

context.watch().counts: Provider가 count 값이 변화하는지 감지하고 변경되면 변경된 값을 화면에 표시함.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:provider_example/providers/counts.dart';

class Counter extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('Counter');

    return Text(
      context.watch<Counts>().count.toString(),
      style: TextStyle(
        fontSize: 20,
      ),
    );
  }
}

 

context.read().add(): Provider가 모델에 정의된 (상태를 변경하는) 함수를 호출하고 이 함수들에서 변경된 상태가

위젯에 위치한watch에 감지되면 변경된 상태를 리턴해줌.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:provider_example/providers/counts.dart';

class Buttons extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        ElevatedButton(
            onPressed: () {
              context.read<Counts>().add();
            },
            child: Icon(Icons.add)),
        SizedBox(
          width: 40,
        ),
//        read나 watch를 못쓰면 이렇게 Cousumer를 사용해도 된다.
//        Consumer<Counts>( // Consumer를 사용하여 ElevatedButton을 감쌌다.
//              builder: (_, counter, __) =>
//              ElevatedButton(
//                child: Icon(Icons.remove)
//                onPressed: () {
//                  counter.remove();
//                },
//              ),
//            ),
        ElevatedButton(
            onPressed: () {
              context.read<Counts>().remove();
            },
            child: Icon(Icons.remove))
      ],
    );
  }
}

정리

  • context.watch<T>(): 해당 위젯이 상태값의 변경을 감시함. => Provider.of<T>(context)
  • context.read<T>():: 해당위젯이 상태값을 읽음. 변경 감지X => Provider.of<T>(context, listen: false)
  • context.select<T>():: 해당 위젯이 상태값의 특정 부분만을 감시함.

Provider.of<T>(context)와 context.watch<T>()가 같은가?

4.3.3 이전 버전에서는

모든 조건에서 사용 가능: Provider.of<T>(context),Provider.of<T>(context, listen: false)

특정 조건에서 사용 불가능: context.watch<T>(), context.read<T>() (StatelessWidget이나 StateWidget의 build 안).

하지만 지금은 똑같다..

MultiProvider

여러 Provider를 제공할 수 있게해서 사용함. 실제 프로젝트에서는 한 위젯에서 여려가지 생태값을 필요로 하는 경우들이 있는데 이때 쉽게 Provider 관리를 할 수 있다.

void main() {
  runApp(MultiProvider(providers: [
    ChangeNotifierProvider<ThemeColor>(create: (_) => ThemeColor())
  ], child: MyApp()));
}

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함