공log/[Flutter]
[Flutter] 플러터 #22 - ListenProvider
ming_OoO
2023. 5. 26. 20:38
728x90
ListenProvider에 대해 알아보겠습니다
ListenProvider는 Flutter의 상태 관리 패키지 중 하나인 Riverpod에서 제공하는 기능입니다. ListenProvider는 다른 Provider를 구독하고 해당 Provider가 변경될 때마다 리스닝하고, 이를 기반으로 상태를 업데이트하는 Provider입니다. 이를 통해 동적인 데이터 의존성을 관리하고 상태 변화에 따라 적절한 액션을 수행할 수 있습니다.
1. 개념:
- ListenProvider는 다른 Provider의 상태 변화를 감지하여 자동으로 리스닝하고 상태를 업데이트하는 Provider입니다.
- 다른 Provider의 값을 읽어와 이를 기반으로 새로운 값을 생성하거나 액션을 수행합니다.
- 다른 Provider와 의존성을 가지며, 해당 Provider가 변경될 때마다 리스닝하여 상태를 업데이트합니다.
2. 장점:
- 동적인 데이터 의존성 관리: ListenProvider는 다른 Provider에 의존하므로, 해당 Provider가 변경될 때 자동으로 상태를 업데이트할 수 있습니다.
- 간편한 상태 관리: ListenProvider를 사용하면 상태 변화에 따라 적절한 액션을 수행할 수 있으므로, 복잡한 상태 관리 로직을 간단하게 구현할 수 있습니다.
- 확장성과 유연성: 다양한 Provider를 조합하여 ListenProvider를 사용할 수 있으며, 필요에 따라 상태 변화를 처리하는 로직을 커스터마이즈할 수 있습니다.
3. 사용 방법:
- ListenProvider를 생성할 때, `ref.listen` 메서드를 사용하여 리스닝할 Provider를 지정합니다.
- `ref.listen` 메서드는 ProviderContainer의 참조를 통해 다른 Provider를 읽을 수 있습니다.
- 리스닝할 Provider가 변경될 때마다 제공된 콜백 함수가 호출되어 상태를 업데이트합니다.
- 상태 업데이트는 `ref.read` 또는 `ref.watch`를 통해 필요한 다른 Provider 값을 읽어와 처리합니다.
import 'package:flutter_riverpod/flutter_riverpod.dart';
// 그냥 listen 형태의 StateProvider 선언
final listenProvider = StateProvider<int>((ref) => 0);
- listenProvider는 StateProvider로 선언된 Provider입니다. 초기값으로 0을 가지고 있습니다.
import 'package:ex_state/riverpod/listen_provider.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class ListenProviderScreen extends ConsumerStatefulWidget {
const ListenProviderScreen({Key? key}) : super(key: key);
@override
ConsumerState<ListenProviderScreen> createState() =>
_ListenProviderScreenState();
}
class _ListenProviderScreenState extends ConsumerState<ListenProviderScreen>
with TickerProviderStateMixin {
late final TabController controller;
@override
void initState() {
super.initState();
// initState 단계에서 TabBarView의 컨트롤러 생성
controller = TabController(
length: 10,
vsync: this,
// 문제점이 하나 있다. 여기서 따로 설정을 안 해줄 경우 해당 페이지를 다시 로드할때 맨 처음 StateProvider에서 가리키는 0의 값으로 호출되기에
// initState에서도 StateProvider의 값을 read 해줄 수 있어야함 *주의* initState는 한번만 실행되기에 watch 함수를 사용해선 X
initialIndex: ref.read(listenProvider),
// 초기 인덱스값 지정, 만약 listenProvider를 autoDispose로 해놨다면 매번 0으로 돌아갈 것
);
}
@override
Widget build(BuildContext context) {
// 원리: 다음, 뒤로 버튼이 눌릴 때마다 listenProvider의 값이 변경되면서 밑의 listen 함수를 호출하는 것
// <int> <- 제네릭 선언으로 받는 데이터(previous, next)의 데이터 타입을 미리 선언해줄 수 있음
// previous: 바뀌기 이전의 상태, next: 바뀐 후의 상태
ref.listen<int>(listenProvider, (previous, next) {
// 만약 previous != next 라면 최대 페이지에 도달했다는 뜻이기에
// ex) (9 == 9) -> False 또는 (0 == 0) -> False
if (previous != next) {
controller.animateTo(
next,
);
}
});
return DefaultLayout(
title: 'ListenProviderScreen',
body: TabBarView(
controller: controller,
children: List.generate(
10,
(index) => Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(index.toString()),
ElevatedButton(
onPressed: () {
ref
.read(listenProvider.notifier)
.update((state) => state == 9 ? 9 : state + 1);
// listenProvider.notifier의 상태를 읽어서 state의 값(현재 페이지)이 마지막 페이지 수인 9을 가리키면
// 9로 두고 아니면 1 더하는 형태
},
child: Text('다음'),
),
ElevatedButton(
onPressed: () {
ref
.read(listenProvider.notifier)
.update((state) => state == 0 ? 0 : state - 1);
// listenProvider.notifier의 상태를 읽어서 state의 값(현재 페이지)이 처음 페이지 수인 0을 가리키면
// 0으로 두고 아니면 1 빼는 형태
},
child: Text('뒤로'),
),
],
),
),
),
);
}
}
- ListenProviderScreen 위젯은 ConsumerStatefulWidget을 상속하고, ConsumerState<ListenProviderScreen>을 상속하는 _ListenProviderScreenState 클래스를 가집니다.
- _ListenProviderScreenState 클래스는 TickerProviderStateMixin을 사용하여 애니메이션을 처리할 수 있는 특징을 가지고 있습니다.
- TabController를 initState 메서드에서 초기화하고, listenProvider 값을 초기 인덱스로 설정합니다. 이 때, ref.read(listenProvider)를 사용하여 초기 인덱스 값을 읽어옵니다.
- ref.listen<int>(listenProvider, (previous, next) { ... })를 사용하여 listenProvider의 값 변화를 감지합니다. previous는 변경되기 이전의 상태, next는 변경된 후의 상태를 나타냅니다. 값이 변경될 때마다 controller를 해당 인덱스로 애니메이션을 이동시킵니다.
- TabBarView와 TabController를 사용하여 페이지를 표시하고, 각 페이지마다 해당 인덱스를 표시하고 "다음"과 "뒤로" 버튼을 제공합니다.
- "다음" 버튼과 "뒤로" 버튼을 누를 때마다 listenProvider의 값을 업데이트하여 다음 페이지나 이전 페이지로 이동합니다.
다음은 실행결과입니다.
![]() |
![]() |
- ListenProviderScreen은 10개의 페이지를 가지며, 각 페이지마다 페이지 번호와 "다음"과 "뒤로" 버튼이 표시됩니다.
- 처음 실행했을 때는 0번 페이지가 표시됩니다.
- "다음" 버튼을 누르면 페이지 번호가 증가하고, "뒤로" 버튼을 누르면 페이지 번호가 감소합니다.
- listenProvider의 값 변화를 감지하여 해당 페이지 번호에 맞는 애니메이션을 수행합니다.
ListenProvider는 다른 Provider의 상태 변화를 감지하고, 해당 변화에 따라 상태를 업데이트하고 액션을 수행하는 역할을 합니다. 위의 예시에서는 listenProvider의 값 변화에 따라 페이지 번호와 애니메이션을 조정하여 사용자에게 적절한 페이지를 보여줍니다. 이를 통해 동적인 상태 관리와 상태 간의 의존성을 처리할 수 있습니다.
ListenProvider는 상태 변화에 따라 동적인 의존성 관리와 상태 업데이트를 수행하는 강력한 도구입니다. 다른 Provider를 리스닝하여 상태를 감지하고, 필요한 액션을 수행할 수 있으므로 복잡한 상태 관리를 간편하게 구현할 수 있습니다.
728x90