TCA
iOS 17 아래 버전
@Bindable 은 iOS 17 이후로 제공
@ObservableState 를 사용하기 위해서는 @Perception.Bindable 로 사용해야 한다.
추가로 WithPerceptionTracking 를 해야 정상 동작한다.
Action에도 @CasePathable 를 추가해야 한다.
struct RootView: View {
@Perception.Bindable
private var store: StoreOf<RootFeature>
init(store: StoreOf<RootFeature>) {
self.store = store
}
var body: some View {
WithPerceptionTracking {
TabView(selection: $store.selectedTab.sending(\.tabSelected)) {
HomeView(store: store.scope(state: \.home, action: \.home))
.tabItem { Text(RootTab.home.title) }
.tag(RootTab.home)
FeedView(store: store.scope(state: \.feed, action: \.feed))
.tabItem { Text(RootTab.feed.title) }
.tag(RootTab.feed)
TodayView(store: store.scope(state: \.today, action: \.today))
.tabItem { Text(RootTab.today.title) }
.tag(RootTab.today)
MyView(store: store.scope(state: \.my, action: \.my))
.tabItem { Text(RootTab.my.title) }
.tag(RootTab.my)
}
}
}
}
@Reducer
struct RootFeature {
@ObservableState
struct State: Equatable {
var selectedTab: RootTab = .home
var home: HomeFeature.State = .init()
var feed: FeedFeature.State = .init()
var today: TodayFeature.State = .init()
var my: MyFeature.State = .init()
}
@CasePathable
enum Action {
case home(HomeFeature.Action)
case feed(FeedFeature.Action)
case today(TodayFeature.Action)
case my(MyFeature.Action)
case tabSelected(RootTab)
}
var body: some ReducerOf<Self> {
Scope(state: \.home, action: \.home) {
HomeFeature()
}
Scope(state: \.feed, action: \.feed) {
FeedFeature()
}
Scope(state: \.today, action: \.today) {
TodayFeature()
}
Scope(state: \.my, action: \.my) {
MyFeature()
}
Reduce { state, action in
switch action {
case .home, .feed, .today, .my:
return .none
case let .tabSelected(selectedTab):
state.selectedTab = selectedTab
return .none
}
}
}
}
GeometryReader 내부도 WithPerceptionTracking로 감싸야 한다
외부 뿐만 아니라 GeometryReader를 사용하는 경우 내부에도 감싸야 함
WithPerceptionTracking {
VStack {
GeometryReader { proxy in
WithPerceptionTracking {
Path { path in
path.move(to: CGPoint(x: proxy.size.width / 2, y: proxy.size.height / 2))
path.addLine(to: CGPoint(x: proxy.size.width / 2, y: 0))
}
.stroke(.primary, lineWidth: 3)
.rotationEffect(.degrees(Double(store.secondsElapsed) * 360 / 60))
}
}
}
}
Last updated