이모저모/SwiftUI
TCA - Pagination TabView 사용
ARpple
2024. 3. 17. 16:26
✅ 기존 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만 갖고 있어 타이머가 잘 작동하는 것을 볼 수 있다!!
