[Flutter] Provider 예제

향신료·2023년 10월 27일
0

Flutter의 상태관리

목록 보기
4/4

기초 사용법을 익히기 위해 Provider를 통한 + , - 카운터 앱 예제를 만들어보도록 하겠습니다.

Bloc를 사용한 예제는 아래 링크를 통해 확인 가능합니다.

https://velog.io/@heemm/Flutter-Bloc-예제









카운터 앱 제작


dependencies:
  flutter:
    sdk: flutter
  provider:

우선, provider 패키지를 프로젝트에 추가하기 위해 pubspec.yaml 파일에 위와 같은 코드를 추가하고 패키지를 가져옵니다.






count_provider


import 'package:flutter/material.dart';

class CountProvider with ChangeNotifier {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners(); // 값 증가 후 상태 변경 알림
  }

  void decrement() {
    _count--;
    notifyListeners(); // 값 감소 후 상태 변경 알림
  }
}

decrement();

CountProvider 내에서 상태의 count 값이 감소시키고 UI 변경을 알립니다.



increment();

CountProvider 내에서 상태의 count 값이 증가시키고 UI 변경을 알립니다.



notifyListeners()

상태가 변경된 것을 구독하고 있는 위젯들에게 알리는 역할을 합니다.

해당 메서드를 호출하지 않는다면 Provider는 상태가 변경되더라도 UI가 리로드 되지 않습니다.








호출 적용 화면


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

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (BuildContext context) => CountProvider(), // 정의한 Provider
			lazy: true, // true의 경우 기본값, 해당 예제는 설명을 위해 정의되었습니다.
      child: const ScaffoldLayout(
      child: ProviderLayout(),
      ),
    );
  }
}

ChangeNotifierProvider

위젯 트리에 ChangeNotifier를 제공하고, 하위 위젯들이 해당 상태를 사용할 수 있도록 해주며, 변경된 상태를 감지하고 이때 위젯을 다시 그리는 Widget입니다.








➕ ChangeNotifierProvider 매개변수

create (필수)

상태 관리 클래스의 인스턴스를 생성함과 동시에 위젯 트리에 새로운 ChangeNotifier 를 제공해 주는 함수로, 필수 매개변수 입니다.



lazy

해당 설정은 create의 ****지정된 ****상태 클래스를 위젯 트리가 처음 빌드 될 때 바로 생성할지 혹은 필요시에 생성할지 설정하는 매개변수입니다.

기본 설정은 true 이며 이는 실제 필요한 경우에만 생성하여 앱의 리소스를 절약할 수 있습니다.

false 설정 시 위젯 트리가 처음 빌드 될 때 상태 클래스가 생성되며, 필요에 따라 초기 상태 설정이 가능합니다.








ProviderLayout

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:velog_exercise/presentation/feat/provider/provider/count_provider.dart';

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

  @override
  Widget build(BuildContext context) {
    final counter = Provider.of<CountProvider>(context);

    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Text(
          '${counter.count}',
          style: const TextStyle(fontSize: 50),
        ),
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            FloatingActionButton(
              heroTag: 'provider_decrement',
              onPressed: () {
                counter.decrement();
              },
              child: const Icon(Icons.remove),
            ),
            FloatingActionButton(
              heroTag: 'provider_increment',
              onPressed: () {
                counter.increment();
              },
              child: const Icon(Icons.add),
            ),
          ],
        )
      ],
    );
  }
}

counter.count

상태 클래스의 count 값을 가져와 사용합니다.

counter.decrement();

상태 클래스의 count 감소 메서드 호출합니다.

counter.increment();

상태 클래스의 count 증가 메서드 호출합니다.








📍 Provider.of<>(context)?


상태가 변경될 때 위젯을 다시 그리도록 하는 Widget입니다.

Provider 패키지에서 제공되는 Provider.of 메서드를 사용하여 상태 클래스인 CountProvider를 현재 context에서 가져오는 역할을 합니다.

이를 통해 가져온 상태 클래스의 데이터나 메서드에 접근 가능하며, 위젯에서 상태 변경이나 값을 불러오는 등의 작업이 가능합니다.








🤔 Screen과 Layout은 왜 나누어져 있나요?


ChangeNotifierProvider를 통해 먼저 ChangeNotifier 를 제공받아야만 하기 때문입니다.

 final counter = Provider.of<CountProvider>(context);

위 코드와 같이 context를 통해 위젯 트리 속 상태 관리 클래스의 인스턴스를 찾아 구독을 하게 되는데


이를 아래과 같이 진행하게 된다면 상태 관리 클래스가 생성되기도 전에 구독을 시도하기에 에러가 발생합니다.

즉, 존재하지 않는 것에 대한 방황을 하게 된다고 볼 수 있습니다.


에러 발생 예제 코드

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

  @override
  Widget build(BuildContext context) {
		final counter = Provider.of<CountProvider>(context);

    return ChangeNotifierProvider(
      create: (BuildContext context) => CountProvider(),
      child: const ScaffoldLayout(
      child: Column(
		      mainAxisAlignment: MainAxisAlignment.center,
		      children: [
		        Text(
		          '${counter.count}',
		          style: const TextStyle(fontSize: 50),
		        ),
		        Row(
		          mainAxisAlignment: MainAxisAlignment.center,
		          children: <Widget>[
		            FloatingActionButton(
		              heroTag: 'provider_decrement',
		              onPressed: () {
		                counter.decrement();
		              },
		              child: const Icon(Icons.remove),
		            ),
		            FloatingActionButton(
		              heroTag: 'provider_increment',
		              onPressed: () {
		                counter.increment();
		              },
		              child: const Icon(Icons.add),
		            ),
		          ],
		        )
		      ],
		    )
      ),
    );
  }
}


에러 발생 코드를 제외한 해당 코드들의 전문은 Github 레파지토리에서 확인 가능합니다!



공식 문서
하위 링크를 통해 더욱 다양한 예제와 위젯을 볼 수 있으니 참고하시면 좋을 듯 합니다!

Provider 공식 한글화 문서

profile
드문드문 기초 정보를 올리는 블로그

0개의 댓글