getter
- getter는 (private) 변수의 값을 안전하게 받아오는 메서드
- 들어가선 안되는 값을 걸러줌
- ex) age 변수는 나이를 담는 값인데 음수
setter
- setter는 (private) 변수의 값을 안전하게 할당해주는 메서드
- 마찬가지로 변수에 들어가선 안되는 값을 걸러줌
import 'package:flutter/material.dart';
class TabPageIndexProvider extends ChangeNotifier{
// 눈에 보여질 화면의 순서값
// 하단 네비게이션의 선택한 메뉴 번호
int _currentPageIndex = 0;
// currentPageIndex 라는 이름의 getter를 통해 외부에서 _currnetPageIndex 값을 읽을 수 있게 함
// 여기서 => 는 람다 또는 단일 표현식을 정의하는 데에 사용되는 기호
// 이 기호는 함수 본문이 단일 표현식으로만 구성되어있을 때 사용가능.
int get currentPageIndex => _currentPageIndex;
void setCurrentPageIndex(int index){
_currentPageIndex = index;
notifyListeners();
}
}
ChangeNotifierProvider(
create: (_) => Counter(),
child: MyApp(),
)ChangeNotifierProvider(
create: (context) => Counter(context),
child: MyApp(),
)
Consumer
- Provider로부터 제공받은 데이터를 구독하고, 해당 데이터가 변경 될 때마다 자신의 하위 위젯들을 다시 빌드함
Provider version 4.1 부터 사용 가능한 메서드.
프로바이더에 새로운 기능을 더할 수 있게 해줌.
프로바이더 오브젝트는 위젯임. (따라서 다른 위젯에서 가능한 것은 프로바이더에서도 가능)
Context.watch
- BuildContext의 확장 메소드
Context.read
- BuildContext의 확장 메소드
- 형식 context.read() → T
- 타입 T의 오브젝트를 찾아서 그 오브젝트를 리턴해줌
- provider.of(context, listen: false) 와 같은 역할
- Provider로 부터 값을 읽지만, 해당 값이 변경되어도 위젯을 리빌드 하지 않음
(= 수동 리빌드)- 주의)
하지만 **`context.read`**를 사용하여 읽을 수 없는 것은 다음과 같습니다:
1. Provider 트리에 존재하지 않는 객체: 만약 해당 타입의 객체가 Provider 트리에 존재하지 않으면 **`context.read`**를 사용하여 읽을 수 없습니다.
2. **`FutureProvider`**나 **`StreamProvider`**와 같은 비동기 Provider: 이러한 Provider는 비동기 작업을 수행하고 해당 결과를 제공하므로 즉시 값을 읽을 수 없습니다.
- (provider 트리 코드 예시)
```dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Provider 트리의 루트에 MultiProvider를 사용하여 상태를 관리하는 Provider를 제공함
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => Counter()), // Counter 클래스로부터 상태를 관리하는 Provider 제공
Provider(create: (_) => UserService()), // UserService 클래스로부터 의존성을 주입하는 Provider 제공
],
child: MaterialApp(
title: 'Provider Example',
home: MyHomePage(),
),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 여기서 Counter 객체를 Provider 트리에서 읽음
final counter = context.read<Counter>();
return Scaffold(
appBar: AppBar(
title: Text('Provider Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Counter Value:',
),
Text(
'${counter.value}', // Counter 객체의 상태를 사용하여 UI를 업데이트함
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// FloatingActionButton 클릭 시 Counter 객체의 상태를 변경함
counter.increment();
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class Counter with ChangeNotifier {
int _value = 0;
int get value => _value;
void increment() {
_value++;
notifyListeners(); // 상태 변경을 리스너에 알림
}
}
class UserService {
// UserService 클래스는 사용자 정보를 가져오는데 사용됨
}
```
⇒ 따라서 일반적으로 UI 업데이트가 필요한 경우 ‘watch’를 사용하고, 값만 필요한 경우 ‘read’를 사용한다.
Context.select
- context.select<T, R>(R selector(T value)) → R
- 네임이 변할 때만 해당 위젯을 다시 빌드 함.
- T = Provider 로 부터 제공되는 전체 상태 객체의 타입
- R = 선택된 상태 부분의 타입. 즉 ‘selector’ 함수가 반환하는 타입.