티스토리 뷰
아래 움짤처럼 여러 화면에서 상태를 공유해야할때 어떻게 해야하는지 State management 문서를 살펴보겠습니다.
1) 선언적으로 생각하기
우선 선언적으로 생각하라고 합니다. SwiftUI 처럼 state가 바뀌면 뷰를 아예 다시 그리는 컨셉 🆗👌
2) 임시상태 vs 앱상태 (Ephemeral state vs app state)
그 다음에 임시 상태와 앱상태를 구분하라고 합니다. (Ephemeral state vs app state)
임시상태는 말그대로 단일 위젯에만 딱 포함되는 상태입니다. (다른 위젯들이 이 위젯의 상태에 대해 몰라도됨)
그리고 사용자가 앱을 닫았다가 다시 시작하면 초기값으로 재설정되도 되는 상태입니다.
이런 경우 setState()를 써서 상태관리를 해주면 됩니다.
앱상태는 앱의 여러 화면에 대해서 공유하고 싶고 일시적이지 않은 상태를 말합니다.
예를 들어 이런 것들을 앱상태라고 합니다.
앱 상태 관리를 어떻게 하는지는 아래에서 살펴볼게요-!!
아래 그림으로 앱상태와 임시상태를 나눠볼 수 도 있겠습니다.
3) 앱상태관리하기 with Provider - Provider가 필요한 이유
옵션문서를 보면 provider, Redux, BLoC / Rx, MobX 등 다양한 선택지들이 있는데요
문서에서는 provider를 소개하고 있습니다.
그 전에 Provider가 왜 필요한지 살펴볼게요!!
이런 앱이 있다고 해보겠습니다.
위젯 트리는 이렇게 되어있습니다.
MyListItem은 카트에 자신을 추가 할 수 있어야합니다. 그리고 현재 표시된 항목이 이미 카트에 있는지 여부를도 확인할 수 있어야합니다.
그러면 Cart 상태를 어디에 두어야할까요?!?!
Flutter에서는 특정 상태를 사용하는 위젯들 위에 특정 상태를 두는게 합리적이라고 합니다.
왜냐면 '선언적으로 생각하기'에서 본 것 처럼 UI를 변경하려면 다시 빌드해야하기 때문입니다.
즉 MyListItem와 MyCart의 위인 MyApp에 Cart 상태를 두면
Cart상태가 변할때 MyApp이 다시 빌드되고 하위 위젯들도 같이 빌드되면서 MyListItem와 MyCart가 업데이트 되게 되는 것입니다.
이제 Cart 상태를 어디 둘지 알았으니까 Cart 상태에 어떻게 접근할 수 있는지 살펴볼게요-!!
MyListItem은 Cart에 어떻게 접근할 수 있을까요?!
가장 간단한 방법은 MyListItem이 콜백을 넘겨주서 이 아이템이 클릭될때 콜백을 실행하도록 하는 것입니다.
하지만!!
위젯트리가 늘어난다면 위젯에서 위젯으로, 또 위젯에서 위젯으로,, 많은 콜백을 전달해야되는 방법입니다,,
(근데 InheritedWidget, InheritedNotifier, InheritedModel 을 사용하면 상태를 자손에게 전달할 수 있는 더 편한 방법이 있다고는 합니다.)
그래서 우리는 Provider를 써보도록 하겠습니다0!! 이것을 쓰면 콜백이나 InheritedWidget에 대하여 걱정할 필요가 없다고 합니다.
(Provider는 따로 설치해야하는 패키지 입니다. )
4) 앱상태관리하기 with Provider - Provider의 컨셉
Provider에는
세가지 컨셉이 있습니다,
- ChangeNotifier
- ChangeNotifierProvider
- Consumer
ChangeNotifier
ChangeNotifier는 리스너에게 변경 알림을 제공하는 Flutter SDK에 포함 된 간단한 클래스입니다. (flutter:foundation 안에 있는 클래스입니다.)
즉 무언가가 ChangeNotifier 타입이면 우리는 그것의 변화들을 구독할 수 있습니다.
Observable같은 것이라고 하네요
Provider에서는 ChangeNotifier가 앱 상태를 캡슐화하는 한 방법이라고 합니다.
예를 들어 이렇게 CartModel이 ChangeNotifier를 extends하게 하고
카트에 아이템이 추가될때다 카트가 다 비워질때
notifyListeners() 를 call하도록 해줄 수 있습니다.
이 메소드를 부르면 app의 UI도 업데이트 된다고 합니다.
이런식으로 unit test code도 작성할 수 있다고 합니다.
ChangeNotifierProvider
ChangeNotifierProvider는 자손들에게 ChangeNotifier 인스턴스를 제공해주는 친구라고 합니다.
이 클래스는 provider 패키지안에 있습니다.
우리는 ChangeNotifierProvider를 어디에 둘지 위에서 이미 결정했습니다. 바로 MyApp에-!!
MyApp을 아래와 같이 ChangeNotifierProvider로 감싸주세요
만약 여러 클래스를 제공하고 싶다면 MultiProvider라는 것도 있다고 합니다.
Consumer
Consumer를 통해서 앱상태에 접근해줄 수 있습니다.
아래 코드처럼 Consumer에 액세스하려는 모델의 타입(우리는 CartModel)을 지정해주면 됩니다.
그리고 builder는 ChangeNotifier가 변경될때마다 호출되는 함수입니다.
즉 CartModel에서 notifyListeners() 가 호출되면 모든 Consumer<CartModel>의 builder 메소드가 호출됩니다.
그리고 위의 예제처럼 그냥 Text를 리턴해주는 것 말고
Consumer위젯에 deep widget tree를 그리고 싶다면
이렇게 하지말고
이렇게 하라고 합니다.
5) 앱상태관리하기 with Provider - Provider.of
때로는 UI를 변경하기 위해 모델의 데이터가 필요하지는 않지만 모델의 데이터에 액세스 하고 싶을때가 있습니다.
예를 들어 ClearCart 버튼은 카트의 내용물을 표시 할 필요가 없으며 clear( )메서드 를 호출하기만하면 됩니다 .
이때 Consumer<CartModel>를 쓰는 것은 낭비입니다.
다시 빌드할 필요가 없는 위젯을 다시 빌드하도록 프레임워크에 요청하는 것이니까요-!!
그럴땐 Provider.of 를 쓰면 됩니다. (listen을 false로 해서)
그러면 notifyListeners가 불려도 이 위젯은 다시 그려지지 않게 됩니다.
Reference
flutter.dev/docs/development/data-and-backend/state-mgmt/simple
'🤼♀️ > Flutter' 카테고리의 다른 글
[Flutter] iOS, 안드로이드에서 로컬 서버에 접속하기 (1) | 2020.09.25 |
---|---|
[Flutter] 화면전환 (Navigator, CupertinoPageRoute) (0) | 2020.09.25 |
[Flutter] Textfield에서 text가져오기 (0) | 2020.09.22 |
[Flutter] 플러터 프로젝트에 Image 파일 넣기 + 커스텀 탭바 아이콘 (0) | 2020.09.19 |
[Flutter] NavigationBar, TabBar의 border 없애기 (0) | 2020.09.19 |
- Total
- Today
- Yesterday
- PencilKit
- Django FCM
- flutter build mode
- METAL
- Flutter Spacer
- Flutter Text Gradient
- SerializerMethodField
- Sketch 누끼
- Flutter Clipboard
- Dart Factory
- 장고 URL querystring
- DRF APIException
- ribs
- flutter deep link
- drf custom error
- flutter 앱 출시
- Flutter 로딩
- 플러터 싱글톤
- github actions
- ipad multitasking
- Flutter getter setter
- cocoapod
- Python Type Hint
- 장고 Custom Management Command
- Django Heroku Scheduler
- flutter dynamic link
- 플러터 얼럿
- Django Firebase Cloud Messaging
- Watch App for iOS App vs Watch App
- 구글 Geocoding API
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |