플러터에서 상태 관리를 관리하는 패턴을 포스트 해 가도록 하겠습니다. 플러터 상태 관리에서 알아볼 주제로는 첫째로 stateful 위젯과 stateless 위젯을 사용하는 로컬 상태 관리, 둘째로 위젯 트리 내에서 사용하는 share common state, 마지막으로 BLoC 패턴을 사용하는 방법으로 분류해 볼 수 있을 것 같습니다.
이번 글은 상태 관리 포스팅의 첫 번째로 선언형 상태 관리에 대해 알아보도록 하겠습니다.
다음 내용을 다루고 있습니다.
- 애플리케이션 아키텍처와 상태
- 명령형(Imperative) 상태관리
- 선언형(Declarative) 상태 관리
- 명령형, 선언형 상태 관리 비교 정리
애플리케이션 아키텍처와 상태
전문적인 아키텍처 말고 누구나 떠올릴 수 있는 간단한 아키텍처를 생각해 보겠습니다. 일반적인 모바일앱의 아키텍처를 생각해보면 프런트 앤드에는 일반적으로 세 가지 주요 영역으로 나눠 생각해 볼 수 있는데요. 첫째로 유저 인터페이스(UI)이고, 둘 째는 화면의 특정 시점의 상태 값 혹은 가지고 있는 정보, 마지막으로 백엔드와 상호 작용하는 서비스 로직으로 나눠볼 수 있습니다. 프런트 앤드의 짝꿍인 백엔드 쪽을 생각해보면 API의 세트들과, DB와 같은 스토리지 시스템으로 역할을 나눠서 생각해 볼 수 있습니다.
flutter앱에서 말하는 상태 관리는 프런트 엔드의 영역에서 두 번째에 해당하는 상태 값 영역으로 즉 앱의 로컬 상태 관리를 중점으로 생각해 보겠습니다. 여기서 말하는 로컬 상태 관리는 모바일 앱에서 장기적으로 저장되는 상태를 말하는 것이 아니라 단기적인 상태를 의미합니다. 예를 들어 화면에 어떠한 데이터들로 채워졌는지 표현하는 일시적인 상태로, 체크 박스가 체크되었는지와 같은 것들입니다.
상태 관리
결론적으로 이야기하면 플러터에서는 대부분의 경우 선언형 상태 관리를 사용하게 됩니다. 선언형 상태 관리를 이해하기 위해서 반대되는 개념에 있는 명령형 상태관리를에 대해 알아보고 비교해 보도록 하겠습니다.
명령형(Imperative) 상태관리
여기 아래에 createSquare함수를 사용해서 상자 만드는 의사 코드가 있습니다.
box1 = createBox(Colors.Blue);
createBox를 호출하면서 상자 생상을 전달해주고 있습니다. 이제 화면에 파란 상자가 만들어졌습니다. 우리가 만든 상자는 화면에서 시간이 지남에 따라 상태를 변경하게 됩니다. 상자는 그대로 유지하고 내부 상태 값인 색상을 변경해야 합니다.
box1 = createBox(Colors.Blue);
box1.setColor(Colors.Red);
사각형을 빨간색으로 만들기 위해 setColor함수를 호출한다고 가정하고 위 코드처럼 setColor메서드에 Red를 전달하면 상자의 상태가 변경됩니다. 이상할 것 없는 코드처럼 보이지만 여기서 생각해봐야 할 점은 색상인 내부 상태와 UI인 상자가 너무 단단히 묶여 있다는 것입니다. 위에서 다룬 간단한 예는 UI의 상태 처리가 간단하게 보입니다. 하지만 응용 프로그램이 점점 더 커지고 비동기 시나리오가 등장하면서부터 UI개체의 내부 상태를 응용 프로그램의 전체 상태와 동기화하는 것이 매우 까다로울 수 있습니다. 복잡성 증가로 인해 UI의 여러 위치에 동일한 숫자를 표시해야 하지만 표시되지 않는 경우가 발생할 수도 있습니다. 선언형 상태 관리를 알아볼 때가 왔습니다.
선언형(Declarative) 상태 관리(혹은 반응형 상태 관리)
이제 명령형 상태 관리를 하는 대신에 선언형 다른 말로 반응형 상태관리를 생각해보겠습니다.
state = new State(Colors.Blue);
여기 상태 객체를 만들었습니다. 이 객체는 시각적 표현은 존재하지 않고 오직 앱의 어떠한 상태만 가지고 있습니다. 그리고 상태를 파란색으로 초기화하였습니다. 그런 다음 상태를 전달해서 상자를 만들겠습니다.
state = new State(Colors.Blue);
createBox(state);
결과적으로 이전과 같은 파란 상자가 만들어졌습니다. 결과는 같지만 애플리케이션의 상태는 UI와 분리됩니다. 이제 상태를 빨간색으로 변경하고 싶을 때는 해당 상태 개채를 변경하면 됩니다.
state.setColor(Colors.Red)
상태를 변경하였고 UI를 재생성하기 위해 업데이트된 상태를 전단해서 새 상자를 다시 만들 수 있습니다. 뭔가 플러터의 코드 패턴과 비슷해 보이시나요?
state.setColor(Colors.Red)
createBox(state);
이렇게 하므로 앱의 UI에서 애플리케이션의 상태를 명확하게 분리할 수 있습니다. 또한 애플리케이션의 렌더링을 최적화하는 기능을 비롯한 많은 이점을 제공해줍니다. 앱의 상태가 변경됨에 따라 값의 변경이 많이 발생하는 경우 렌더링 주기를 지속적으로 트리거할 수 있게 되고 앱이 유동적으로 보이게 될 것입니다.
명령형, 선언형 상태 관리 비교
- 명령형은 상태가 분산되어 있는 반면, 선언적 상태는 상태를 담는 컨테이너로 중앙 집중화되어 관리하게 됩니다. 명령형의 상태가 분산되어있다는 말은 예를 들어, 메일의 도착 알림이 우측 유저 아이콘과 메일함 아이콘에 표시되어야 할 경우 상태가 UI에 따로따로 분산되어 있습니다.
- 명령형은 상태의 동기화가 어려울 수 있습니다. 프로그램이 복잡해짐에 따라 여러 곳에 상태를 업데이트해줘야 한다면, 서로 동기화되지 않는 이상한 동작이 발생할 수 있습니다. 선언적 상태에서는 일반적으로 동기화가 필요하지 않습니다. 일반적으로 앱의 상태는 하나의 진실 소스(Single Sourece of Truth, SSOT)에 보관되므로 해당 상태가 조작되는 곳은 단 한 곳뿐입니다.
- 명령형 모델을 사용하면 앱을 잘 최적화했다고 가정했을 때 렌더링 오버헤드가 최소화되지만, 간단한 문제는 아닙니다. 선언적 모델이 제공하는 이점은 앱의 프레임워크(플러터)에 렌더링을 위임한다는 것입니다. 따라서 앱을 렌더링 하는 시기와 방법에 대한 최적화는 중앙 집중화되므로 앱을 개발할 때 이에 대해 걱정할 필요가 없습니다.
여기까지 수고하셨습니다.
저도 공부하면서 글을 정리하는 것이라 부족한 점이 많습니다. 잘못된 개념이나 좀 더 자세히 다뤘으면 하는 점이 있다면 댓글 남겨주세요.
다음 상태 관리 포스트는 Stateless Widget로 이어집니다.
'프로그래밍 > Flutter' 카테고리의 다른 글
[flutter 상태관리] 3. stateless widget 실습 (0) | 2022.06.01 |
---|---|
[flutter 상태관리] 2. stateless widget (스테이트리스 위젯) (0) | 2022.05.31 |
[flutter] Dart, json_annotation 패키지, json 자동 직렬화 (0) | 2022.05.28 |
[flutter] Dart, JSON 수동 직렬화(Serialization) 하기 (0) | 2022.05.17 |
[Flutter] Dart, 비동기 처리의 에러 처리 (0) | 2022.05.10 |
댓글