20191019
Flutter State
공식 문서
넓게 보면 앱이 실행되는 동안 메모리에 있는 모든 것들이 State 입니다. 폰트, 앱의 모든 asset들, 텍스쳐 들을 전부 다 포함합니다. 하지만 이 모든 State를 우리가 관리할 수 있는 것은 아닙니다. 그러니 “필요할 때 UI를 다시 빌드 하기 위해서 필요한 모든 것” 이라고 State 라고 정의하는 것이 더 유용합니다. 우리가 다룰 수 있는 state 를 다시 두 가지 유형으로 나눌 수 있습니다.
Ephemeral state vs App state
임시(Ephemeral) State
UI state, local state 라고도 부릅니다. 하나의 위젯 안에서 사용하는 state를 말합니다.
예시
- PageView에서의 현재 페이지
- 복잡한 애니메이션의 현재 진행상황
- BottomNavigationBar에서의 현재 선택된 탭
그냥 간단하게 바꾸면 됩니다. 어려운 기술들을 사용하지 않아도 됩니다. 그저 StatefulWidget 이면 충분합니다. State, setState 콜백으로 관리합니다.
App state
앱의 여러 부분에서 공유되는 state. shared state 라고도 부릅니다.
예시
- User 환경 설정
- 로그인 정보
- SNS 앱에서의 알림
- 쇼핑 앱에서의 장바구니
- 뉴스 앱에서의 기사를 읽었는지 안 읽었는지 여부
다양한 기법들을 사용해서 State를 관리합니다.
명확한 구분 규칙은 없습니다. 보통 State, setState() 로만 관리하고 하나의 위젯에서만 이용되는 state 를 ephemeral state라고 합니다.
app state 관리
state의 위치
상태를 사용하는 위젯 위에서 state를 관리하는 게 좋습니다. 선언적 프레임 워크에서는 메소드를 이용해서 위젯을 변경하는게 아니라 위젯 내부의 내용이 변할 때마다 새로운 위젯을 만들어 주어야 합니다.
// GOOD
void myTapHandler(BuildContext context){
var cartModel = somehowGetMyCartModel(context);
cartModel.add(item);
}
Widget build(BuildContext context){
var cartModel = somehowGetMyCartModel(context);
return SomeWidget(
// 현재 state 를 이용해서 UI를 한 번 만들어 냅니다.
);
}
State 접근
간단하게는 Callback 함수를 만드는 방법이 있습니다. Callback 함수를 자손 위젯을 만들 때 넣어줍니다. 하지만 여러 장소에서 app state를 변경하려고 하면 계속해서 콜백을 만들어야되는 단점이 있습니다.
@override
Widget build(BuildContext context){
return someWidget(
// 위와 동일
MyListItem(myTapCallback),
);
}
void myTapCallback(Item item){
print('user tapped on $item');
}
InheritedWidget, InheritedNotifier, InheritedModel 을 쓰는 방법도 있습니다. 이런 위젯을 이용하면 data나 service를 위젯 트리 상 자손에게 제공 할 수 있습니다.
InheritedWidget을 래핑한 provider를 사용하는 방법은 좀 더 간단합니다. 3가지 개념을 이해해야 합니다.
- ChangeNotifier
- ChangeNotifierProvider
- Consumer
ChangeNotifier는 변화가 있다는 것을 CN을 구독하고 있는 위젯에게 알림을 보냅니다. ChangeNotifierProvider는 위젯 트리 상 CNP 아래에 있는 위젯들에게 CN 인스턴스를 제공합니다. Consumer 를 이용해서 app state를 사용합니다.
아니면 MVC, BLoC 같은 다른 디자인 패턴을 사용하는 방법도 있습니다.