코드 전문
import ComposableArchitecture
import SwiftUI
private let readMe = """
This screen demonstrates how to show and hide views based on the presence of some optional child \
state.
The parent state holds a `Counter.State?` value. When it is `nil` we will default to a plain \
text view. But when it is non-`nil` we will show a view fragment for a counter that operates on \
the non-optional counter state.
Tapping "Toggle counter state" will flip between the `nil` and non-`nil` counter states.
"""
@Reducer
struct OptionalBasics {
@ObservableState
struct State: Equatable {
var optionalCounter: Counter.State?
}
enum Action {
case optionalCounter(Counter.Action)
case toggleCounterButtonTapped
}
var body: some Reducer<State, Action> {
Reduce { state, action in
switch action {
case .toggleCounterButtonTapped:
state.optionalCounter =
state.optionalCounter == nil
? Counter.State()
: nil
return .none
case .optionalCounter:
return .none
}
}
.ifLet(\.optionalCounter, action: \.optionalCounter) {
Counter()
}
}
}
struct OptionalBasicsView: View {
let store: StoreOf<OptionalBasics>
var body: some View {
Form {
Section {
AboutView(readMe: readMe)
}
Button("Toggle counter state") {
store.send(.toggleCounterButtonTapped)
}
if let store = store.scope(state: \.optionalCounter, action: \.optionalCounter) {
Text(template: "`Counter.State` is non-`nil`")
CounterView(store: store)
.buttonStyle(.borderless)
.frame(maxWidth: .infinity)
} else {
Text(template: "`Counter.State` is `nil`")
}
}
.navigationTitle("Optional state")
}
}
#Preview {
NavigationStack {
OptionalBasicsView(
store: Store(initialState: OptionalBasics.State()) {
OptionalBasics()
}
)
}
}
#Preview("Deep-linked") {
NavigationStack {
OptionalBasicsView(
store: Store(
initialState: OptionalBasics.State(
optionalCounter: Counter.State(
count: 42
)
)
) {
OptionalBasics()
}
)
}
}
리드미 해석
This screen demonstrates how to show and hide views based on the presence of some optional child state.
The parent state holds a `Counter.State?` value. When it is `nil` we will default to a plain text view. But when it is non-`nil` we will show a view fragment for a counter that operates on the non-optional counter state.
Tapping "Toggle counter state" will flip between the `nil` and non-`nil` counter states.
이 화면은 일부 optional 하위 상태의 존재 여부에 따라 보기를 표시하고 숨기는 방법을 보여줍니다.
부모 상태는 `Counter.State?` 값을 보유합니다. 이 값이 `nil`이면 기본적으로 일반 텍스트 보기가 표시됩니다. 그러나 `nil`이 아닌 경우 옵션이 아닌 카운터 상태에서 작동하는 카운터에 대한 뷰 조각을 표시합니다.
"카운터 상태 전환"을 탭하면 `nil`과 `nil`이 아닌 카운터 상태 간에 전환됩니다.
Reducer{ ... }.ifLet(\.State, \.Action)
Reducer뒤에서 iflet을 활용하 state와 Action이 Nil이 아닐경우에 Store을 생성하게 한다. Action은 Enum이기에 State의 특정 Property 가 nil이 아닐 경우 Store을 생성한다. 버튼을 누를 경우 Store에서 Counter의 State를 생성하게 된다.
// Reducer
var body: some Reducer<State, Action> {
Reduce { state, action in
switch action {
case .toggleCounterButtonTapped:
state.optionalCounter =
state.optionalCounter == nil
? Counter.State() // Counter의 State을 생성한다.
: nil
return .none
case .optionalCounter:
return .none
}
}
.ifLet(\.optionalCounter, action: \.optionalCounter) { // 만약 State가 존재할 겨우 Store 생성
Counter()
}
}
}
// View
Button("Toggle counter state") {
store.send(.toggleCounterButtonTapped)
}


게시물은 TCA 라이브러리의 CaseStudies를 직접 작성해보고 어떻게 작동하는지에 대해서 공부하기 위해서 작성했습니다.