이 글은 Riverpod 공식문서를 참조 하였습니다.
이전글에서 "ref" 객체를 얻어오는 방법에 대해 알아봤습니다.
이제 "ref" 객체의 사용방법에 대해 알아보겠습니다.
ref 주요기능 3가지
- ref.watch
- 프로바이더의 값을 얻고 값의 변화를 감지합니다.
- 값의 변화를 감지하면 Widget을 재빌드 하거나 해당 값을 구독하고 있는 곳에 변경된 상태값을 전달 합니다. - ref.listen
- 프로바이더의 상태값을 구독하거나
- 상태값이 변했을때 어떠한 행위를 취해야할 경우 사용합니다. - ref.read
- 프로바이더의 상태값을 얻습니다.
- 이벤트 콜백함수에 사용하기 유용합니다.
- 예를 들어 버튼의 onPressed 콜백 함수에서 프로바이더의 필요한 상태값을 얻기위해 사용가능합니다.
기능을 구현할때는 ref.read 또는 ref.listen 보다 ref.watch 사용을 권장하고 있습니다.
ref.watch를 사용하면 reactive와 declarative에 가까워지고 애플리케이션의 유지보수가 편리 해집니다.
ref.watch를 사용해서 프로바이더 관찰하기
위젯의 build 메소드 내부 또는 프로바이더 내부에서 ref.watch를 사용함으로써 프로바이더의 상태 값을 구독할 수 있습니다.
예를 들어, 프로바이더에서 ref.watch를 사용하여 복수의 프로바이더와 결합해 새로운 값을 생성 할 수도 있습니다.
class MyApp extends ConsumerWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
//ref를 사용해 프로바이더 구독하기
final counter = ref.watch(counterProvider);
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("Riverpod Study")),
body: Center(
child: Column(
children: [
Text(counter.toString()),
ElevatedButton(
onPressed: () {
ref.read(counterProvider.notifier).state++;
},
child: Text("버튼"),
),
],
),
),
),
);
}
}
해당코드는 버튼을 누르면 counter가 증가하여 증가된 값이 화면에 보여지게 됩니다.
해당코드는 ConsumerWidget을 상속받았습니다. 이건 StatelessWidget 과 같습니다.
StatelessWidget 은 정적화면에서 사용하는건 알고계시죠?
값이 변해도 화면의 변화가 일어나지 않습니다. 상태가 없기 때문이죠.
하지만 버튼을 누르면 화면이 바뀝니다.
이유는 ref.watch로 값의 변화를 감지하고 있다가 값의 변화가 생기면 재빌드를 해주기 때문입니다.
버튼의 onPressed 메소드에 구독하고있는 프로바이더에 상태를 변경하는 코드가 있습니다.
해당 버튼이 눌리면 값의 변화가 일어나고 ref.watch에서 감지해 재빌드하여 화면을 바꿔주는것입니다.
ref.listen 사용해보기
ref.listen은 ref.watch와 비슷하게 작동합니다.
차이점은
ref.watch는 프로바이더의 상태값이 변경되면 widget/provider를 다시 빌드하지만
ref.listen은 함수를 호출 합니다.
ref.listen(counterProvider, (previousState, newState) {
print("The new value is $newState");
});
위에 코드처럼 사용할 수 있습니다.
ref.listen은 인자로 프로바이더와, 추가로 콜백함수를 넣어주어야 합니다.
콜백함수에는 2개의 값이 전달 됩니다. 하나는 이전의 상태값, 하나는 갱신된 상태 값입니다.
class MyApp extends ConsumerWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
//ref를 사용해 프로바이더 구독하기
final counter = ref.watch(counterProvider);
ref.listen(counterProvider, (previousState, newState) {
print("The new value is $newState");
});
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("Riverpod Study")),
body: Center(
child: Column(
children: [
Text(counter.toString()),
ElevatedButton(
onPressed: () {
ref.read(counterProvider.notifier).state++;
},
child: Text("버튼"),
),
],
),
),
),
);
}
}
해당 코드는
버튼이 눌리면 ref.read로 프로바이더의 상태를 변경 시켜주고
ref.watch가 상태변경을 감지하고 있다가 변경되면 화면을 재빌드 해줍니다.
ref.listen도 상태변경을 감지하고 있다가 변경되면 함수를 호출 합니다.
ref.listen은 build메소드 안에서 사용도 가능하지만
프로바이더 내부에서도 사용할 수 있습니다.
final counterProvider = StateNotifierProvider<Counter, int>((ref) => Counter(ref));
final anotherProvider = Provider((ref) {
ref.listen<int>(counterProvider, (int? previousCount, int newCount) {
print('The counter changed $newCount');
});
// ...
});
ref.read 사용해보기
ref.read는 어떠한 효과없이 프로바이더의 상태를 얻기위한 방법으로 사용됩니다.
위에서 이미 ref.read를 사용해봤습니다.
ElevatedButton(
onPressed: () {
ref.read(counterProvider.notifier).state++;
},
child: Text("버튼"),
),
버튼이 눌리면 프로바이더의 상태를 얻어와 값만 변경 시켰습니다.
대부분의 ref.read는 이런식으로 사용됩니다.
select
추가적으로 select에 대해 알아보겠습니다.
프로바이더를 감시하는 것은, 그 포로바이더가 공개하는 객체의 모든 속성을 감시합니다.
그러나 특정 경우에서 감시하는 범위를 좁히고 그 범위안의 속성만 모니터링 대상으로 만들 수 있습니다.
예를들어
abstract class User {
String get name;
int get age;
}
프로바이더는 User의 상태값을 가진다고 하면,
Widget build(BuildContext context, WidgetRef ref) {
User user = ref.watch(userProvider);
return Text(user.name);
}
해당 코드에서는 user의 name 값만 사용하고 있습니다.
만약에 ref.watch를 사용하면 User의 age 속성이 변경되면 해당 위젯은 재빌드 될것입니다.
age는 보여주지도 않는데 화면은 재빌드되면서 자원 낭비를 하게 됩니다.
해결 방법은 select 를 사용하는 것입니다.
select는 Riverpod에서 특정 속성만 구독하고 관찰하고 싶을때 사용합니다.
Widget build(BuildContext context, WidgetRef ref) {
String name = ref.watch(userProvider.select((user) => user.name));
return Text(name);
}
이렇게 한다면
User의 값이 변하면, Riverpod은 이 함수를 호출하여 이전 값과 새로운 값을 비교합니다.
비교해서 상태값이 변했다면 (name이 바뀌었다면) Riverpod은 위젯을 재빌드합니다.
비교해서 상태값이 변하지 않았다면 Riverpod은 위젯을 재빌드 하지 않습니다.
'Flutter > Riverpod' 카테고리의 다른 글
Flutter) Riverpod refresh / invalidate - 6 (0) | 2023.01.22 |
---|---|
Flutter) Riverpod Consumer 사용하기 - 5 (0) | 2023.01.22 |
Flutter) Riverpod "ref" 얻기 - 3 (0) | 2023.01.21 |
Flutter) Riverpod 프로바이더란? - 2 (0) | 2023.01.21 |
Flutter) Riverpod 상태관리 시작해보기 - 1 (0) | 2023.01.21 |