Mobile/Flutter

[Flutter] Dive into Flutter State Management. UI = f(state).

개발왕 금골드 2022. 12. 2. 20:10
반응형

Introduce

Flutter의 State

  • 앱 상태가 변경되면 사용자 인터페이스가 다시 그려진다.
  • setState로 Widget의 state를 변경하며, 그때마다 Layer Tree를 다시 만든다.
  • [공식 문서 기준] 언제든지 UI를 재구축하기 위해 필요한 모든 데이터 집합.
  • widget.setText()와 같이 UI 자체를 반드시 변경할 필요 없으며, 상태를 변경하면 UI가 처음부터 다시 만들어진다.

Ephemeral(Local) state

  • Ephemeral state(UI state or local state)는 단일 위젯에 포함할 수 있는 상태이다.
    • 예) PageView 안에 현재 페이지
    • 예) BottomNavigationBar에서 현재 선택된 탭
  • 이러한 상태는 위젯 트리의 다른 부분에 접근할 일이 거의 없기 때문에 상태 관리 기법을 사용할 필요가 없다.
class MyHomepage extends StatefulWidget {
  const MyHomepage({super.key});

  @override
  State<MyHomepage> createState() => _MyHomepageState();
}

class _MyHomepageState extends State<MyHomepage> {
  //앱의 다른 부분에서 _index에 접근할 필요가 거의 없다.
  //또한, 사용자가 앱을 닫았다가 다시 시작해도 _index가 0으로 재설정되어도 상관없다.
  int _index = 0;

  @override
  Widget build(BuildContext context) {
    return BottomNavigationBar(
      currentIndex: _index,
      onTap: (newIndex) {
        setState(() {
          _index = newIndex;
        });
      },
      // ... items ...
    );
  }
}

App state

  • 앱의 많은 부분에서 공유하고자 하는 상태 및 사용자 세션 간에 유지하고자 하는 상태.
    • 예) 사용자 기본 설정
    • 예) 로그인 정보

어떤 특정 변수가 일시적 상태인지 앱 상태인지 구분하는 명확한 규칙은 존재하지 않는다.

앱의 기능이 증가함에 따라 일시적 상태가 앱 상태로 전환될 수도 있다.

State Management

  • Flutter는 선언적 UI를 사용한다. 선언적 UI를 변경하기 위해서는 다시 빌드해야 한다.
  • 다시 말해, 위젯에 대한 메서드를 외부에서 호출하여 위젯을 강제로 변경하는 방법은 권장되지 않는다.
// BAD: DO NOT DO THIS
void myTapHandler() {
  var cartWidget = somehowGetMyCartWidget();
  cartWidget.updateWith(item);
}

// BAD: DO NOT DO THIS
Widget build(BuildContext context) {
  return SomeWidget(
    // The initial state of the cart.
  );
}

void updateWith(Item item) {
  // Somehow you need to change the UI from here.
}
// GOOD
void myTapHandler(BuildContext context) {
  var cartModel = somehowGetMyCartModel(context);
  cartModel.add(item);
}

// GOOD
Widget build(BuildContext context) {
  var cartModel = somehowGetMyCartModel(context);
  return SomeWidget(
    // Just construct the UI once, using the current state of the cart.
    // ···
  );
}
  • 새 위젯은 부모의 빌드 메서드에서만 구성할 수 있으므로 내용을 변경하려면 부모 이상 위치에 있어야 한다.
  • 예를 들어, A Page가 있다면, A Page는 MyApp() 안에 위치해야 한다. state 변경이 일어나면 MyApp()(혹은 A Page의 부모) 안에 있는 A Page를 재구성한다. 따라서, A Page의 수명 주기를 걱정할 필요가 없고 이전 A Page는 사라지고 새로운 A Page로 완전히 대체된다.

Accessing the state

  • (맨 위 이미지 참고) state 변경이 일어나면 부모 위젯에서 해당 위젯을 재구성한다.
  • 만약 다른 위젯 트리 state를 관리해야 하는 경우 콜백을 제공하여 이를 해결할 수 있다. (Dart는 일급 객체이므로 원하는 방식으로 전달이 가능하다.)
  • 그러나, 위 방법으로 다수의 콜백을 전달하였을 경우 이를 관리하는 데 어려움이 있을 수 있다.
  • 대신 provider(혹은 다른 라이브러리)를 사용하여 이러한 접근을 쉽게 사용할 수 있다.
    • provider
    • getX

 
 
참고자료 :
Start thinking declaratively

Start thinking declaratively

How to think about declarative programming.

docs.flutter.dev

 

반응형