본문 바로가기
이모저모/SwiftUI

TCA - Pagination TabView 사용

by ARpple 2024. 3. 17.
✅ 기존 TCA에서 TabView를 사용한 자료들은 TCA viewStore을 사용한 예제만 존재함. (구 버전...)
viewStore를 쓰지 않고 Bindable을 사용한 TCA에서 TabView를 어떻게 자연스럽게 쓸 수 있을까??

✅ TCA 버전 1.9.2

문제점

❗ 타이머 뷰에서 타이머 작동 후, 탭을 스와이프 한 후 돌아오니 타이머 뷰가 사라지는 문제점 발생

 

원인: TabView Swipe 할 때 마다 새로운 Store을 생성하는 하위 뷰

  • Swipe 후, 기존 TimerFeature 내부 타이머 뿐만 아니라 새로운 TimerFeature 내부 타이머도 호출되는 것을 발견
TabView와 연결된 상위 Feature에서 하위 Feature인 TimerFeature의 값을 전파해서 문제를 해결해야겠다고 생각함

해결법: Scope를 이용해 하위 도메인 값 넘기기

1. store.scope를 통한 하위 뷰 store 생성

import SwiftUI
import ComposableArchitecture
struct DoroMainView: View {
    @Perception.Bindable var store: StoreOf<Feature>
    var body: some View {
        WithPerceptionTracking {
            TabView(selection: $store.pageSelection.sending(\.pageMove), content:  {
                AnalyzeView(store: self.store.scope(state: \.anylzeState, action: \.analyze))
                    .tag(DorocatFeature.PageType.analyze)
                TimerView(store: store.scope(state: \.timerState, action: \.timer))
                    .tag(DorocatFeature.PageType.timer)
                SettingView(store: self.store.scope(state: \.settingState, action: \.setting))
                    .tag(DorocatFeature.PageType.setting)
            })
            .tabViewStyle(.page(indexDisplayMode: .never))
        }
    }
    
}

2. Scope 컴포넌트를 이용한 하위 Feature 생성

2-1. 상위 State에 TabView 하위 뷰에서 사용할 State들 생성

@Reducer struct Feature{
		...
    @ObservableState struct State: Equatable{
        var pageSelection: PageType = .timer
        var anylzeState = AnalyzeFeature.State()
        var timerState = TimerFeature.State()
        var settingState = SettingFeature.State()
    }
    ...
  }

 2-2. 상위 Action에 TabView 하위 뷰에서 사용할 Action들 생성

@Reducer struct Feature{
		...
    enum Action:Equatable{
        case pageMove(PageType)
        case timer(TimerFeature.Action)
        case analyze(AnalyzeFeature.Action)
        case setting(SettingFeature.Action)
    }
    ...
}

2-3.  Scope 컴포넌트를 이용해 하위 Feature 생성

@Reducer struct Feature{
		...
	var body: some ReducerOf<Self>{
    	Reduce{ state, action in
            ...
        }
        Scope(state: \.timerState, action: /DorocatFeature.Action.timer) {
            TimerFeature()
        }
        ...
    }
    ...
}

결과

TabView Swipe 후에도 하나의 State만 갖고 있어 타이머가 잘 작동하는 것을 볼 수 있다!!

 

댓글