HIT해
[Flutter] Provider이해와 사용법 / 무한 렌더링 해결하기! 본문
Provider를 사용하다보면 렌더링이 지속적으로 반복하는 경우가 있습니다.
우선 Provider 사용법을 알아봅시다.
watch
-> Provider 변화를 감지해 데이터를 얻고 해당 메소드가 포함된 위젯을 재빌드
read
->Provider의 데이터를 읽고 변경할 수 있다.
select
-> watch와 유사하게 변화를 감지하고 위젯을 재빌드하지만 Provider내의 특정 속성의 변화만을 감지할 수 있다.
select 예시다
class User {
User({required this.name, this.age});
final String name;
final int age;
}
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final userName = context.select((User user) => user.name);
return Text('Hello, $userName');
}
}
그리고 watch로 재빌드 되는 위젯은 watch를 호출하는 위젯과 그 하위의 위젯들이다.
watch예시다
class User {
User({required this.name, this.age});
final String name;
final int age;
}
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final user = context.watch<User>();
return Text('Hello, ${user.name}, you are ${user.age} years old');
}
}
상위가 Stateful이라고 바뀌거나 하위가 Stateless라고 안바뀌는 방식이 아니다
그렇다면 무한 렌더링이 발생되는 경우는 언제일까?
앞서 본 정보들을 나열한다면
첫번째로 최상단 위젯에 watch를 선언하고 무한히 반복되는 상황을 만들었을 경우다.
그런 경우가 언제 있을까.
데이터베이스에서 값을 받아 Provider 변수에 할당하는 함수를 watch로 호출했다고 생각하자.
그렇다면 받아오는 동작은 같은 값이더라도 변화했다고 받아들여 무한히 렌더링이 되는 것이다.
다음은 예시다
class AlarmScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
// get the notifcation message and display on screen
final message = ModalRoute.of(context)!.settings;
// 모달 경로를 가져오고 인수를 가져옵니다. 알림을 위해. 이 메시지를 받으면
context.read<AlarmStore>().getAlarmListData(context);
context.watch<AlarmStore>().AlarmList;
}
}
class AlarmStore extends ChangeNotifier {
var AlarmList;
Future<void> getAlarmListData(BuildContext context) async {
String accessToken = context.read<UserStore>().accessToken;
const String takeYnListUrl = "${CONVERT_URL}/api/v1/pill/inventory/list";
try {
var response = await http.get(Uri.parse(takeYnListUrl), headers: {
'Content-Type': 'application/json',
'accessToken': accessToken,
});
print('response 이거임 $response');
if (response.statusCode == 200) {
print("알람 리스트 수신 성공");
// print(response.body);
// InventoryStore에 응답 저장
var tmp = jsonDecode(utf8.decode(response.bodyBytes));
AlarmList = tmp['takeFalse']["data"];
print("저장한 알람 데이터는?? ${AlarmList['takeFalse']["data"]}");
} else {
// print(response.body);
print("재고 복용 목록 get 수신 실패");
}
} catch (error) {
print(error);
}
notifyListeners();
}
위와 같이 사용할경우 AlarmList에 값을 할당하면 notifyListeners()를 호출하여 상태 변경을 알립니다.
그리고 ChangeNotifier를 구독하고 있는 모든 위젯들에게 상태 변경 알림을 전달하고
값이 변경된 watch로 호출한 위젯과 그 하위 위젯들을 재 렌더링 시킵니다.
그렇기에 위의 경우 무한히 렌더링 되는 경험을 할 수 있습니다.
'Flutter > 개발 노트' 카테고리의 다른 글
[Flutter] 조건에 맞는 데이터 입력하기 (0) | 2024.02.16 |
---|---|
[Flutter] setState와 Provider watch의 차이 (0) | 2024.02.09 |
[Flutter] 카카오 로그인 구현하기 ③ ( 서버 설정 ) (0) | 2024.02.09 |
[Flutter] 팝업 외부 클릭시에도 네비게이터 작동하는 방법 (0) | 2024.02.03 |
[Flutter] 한글깨짐 json.decode 해결방법 (0) | 2024.02.02 |