Skip to content

TCA Store를 보유한 View의 로컬 상태 소유권을 정리한다 #920

Description

@opficdev

목적

TCA Store를 보유한 SwiftUI View에서 Store 이외의 @State가 화면 역할과 관계없이 함께 관리되는 구조를 정리한다.

NavigationStack의 경로는 NavigationRouter가 소유하고, sheet와 push 목적지처럼 사용자 동작에 따라 표시되는 상태는 Feature의 State와 Action이 소유한다. 스크롤 측정처럼 렌더링에만 필요한 일시 상태는 View에 남긴다.

조사 범위와 기준

  • Application, Libraries, Widget의 운영 Swift 소스에서 StoreOf 또는 Store(initialState:)를 사용하는 View 전수 검색
  • 같은 View 타입에 선언된 Store 이외의 @State만 집계
  • 같은 파일의 다른 하위 View 상태는 해당 타입 기준으로 분리
  • Store 자체를 @State로 보관하는 TCA Observation 패턴은 집계에서 제외
  • NavigationRouter를 보관하는 @State는 탐색 경로 소유 방식으로 인정
  • @FocusState, @Environment, @ScaledMetric은 이번 집계에서 제외

조사 결과 Store 이외의 로컬 @State는 7개 View의 10개 속성이다.

상태 소유 기준

NavigationRouter가 소유할 경로

  • TodayView.path를 NavigationRouter<TodayRoute>로 이전
  • HomeView.path를 NavigationRouter<HomeRoute>로 이전
  • SearchView.router는 현재 기준 유지
  • ProfileView.path를 NavigationRouter<ProfileRoute>로 이전

NavigationStack(path:)에 전달하는 경로와 push, pop 조작은 View가 보유한 NavigationRouter를 통해 처리한다. 경로 배열을 Feature State로 옮기거나 새로운 TCA stack 탐색 구조를 도입하지 않는다.

Store가 소유할 표시 상태

  • HomeView.goalPresentation을 HomeFeature의 presentation 상태로 이전
  • RecordDetailView.isEditorPresented를 RecordDetailFeature의 presentation 상태로 이전
  • RecordDetailView.isHistoryPresented를 RecordDetailFeature의 push 목적지 상태로 이전
  • RecordVersionHistoryView.destination을 RecordDetailFeature의 push 목적지 상태로 이전

View의 직접 대입을 Feature Action으로 바꾸고, sheet와 navigationDestination은 Store 상태에 연결한다.

GoalDetailView의 recordEditor, todoLinkSheet, recordDetail, todoDetail 연결은 Store가 presentation 상태를 소유하는 현재 기준으로 유지하며 구현 참고 대상으로 사용한다.

View에 유지할 렌더링 상태

  • TodoListView.headerOffset
  • TodoListView.isScrollTrackingEnabled

두 상태는 스크롤 위치에 따른 헤더 배치와 추적 제어에만 사용되므로 View에 유지한다.

작업 범위 및 완료 조건

  • TodayView, HomeView, ProfileView의 경로 배열을 NavigationRouter로 통일
  • SearchView의 기존 NavigationRouter 동작 유지
  • sheet와 push 목적지 상태 변경을 View의 직접 대입 대신 Feature Action으로 전달
  • Feature가 소유하는 presentation 상태를 SwiftUI의 sheet와 navigationDestination API에 연결
  • 영향받는 Feature 테스트에서 표시와 dismiss 상태 전이 검증
  • 렌더링 전용 로컬 상태의 사용 범위와 View 유지 근거 확인
  • 작업 완료 후 같은 기준으로 운영 Swift 소스를 다시 검색하고 남은 예외 확인
  • UI 계층, 화면 전환 결과, 현재 사용자 동작 보존

기존 이슈와의 관계

  • #879부터 #884는 현재 탐색 경로 소유권을 유지하는 조건으로 View 구성 요소 분리를 다룬다.
  • 이 이슈는 View 분리와 별개로 NavigationRouter, Store, View 사이의 상태 소유권을 정리한다.
  • 같은 파일을 수정할 경우 #879부터 #884의 구현과 충돌하지 않도록 착수 순서를 조율한다.
  • 기존 이슈 본문은 이 이슈 변경만으로 수정하지 않는다.

제외 범위

  • 모든 @State의 일괄 제거
  • NavigationStack 경로를 Feature State로 이전
  • StackState, StackAction, NavigationStackStore 도입
  • NavigationRouter의 공개 계약이나 전체 구조 변경
  • HomeView.searchStore, ProfileView.settingsStore의 생명 주기 재구성
  • @FocusState, geometry 측정값, 애니메이션 진행값을 근거 없이 Feature로 이전
  • UI 디자인과 탐색 결과 변경
  • 관련 없는 View 또는 Feature 정리

검증

  • 영향받는 Feature 단위 테스트
  • DevLog.xcworkspace의 App 스킴 build-only
  • 실제 탐색 제스처와 presentation 동작 검증은 별도 실행 허용 후 수행

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions