[TCA] HigherOrderReducers #1 (Recursion)
목차
- 이번 주제에 대한 간략 설명
- 예제 코드
# 이번 주제에 대한 간략 설명
이번에는 재귀를 통해 View를 관리 하는 방법을 알아볼 예정
# 예제 코드
주요하게 살펴볼 부분
1. State를 rows로 다시 들고 있음으로써 Nested 형태를 구성
2. Action에는 간접 참조를 위해 indirect enum으로 선언
3. Reducer에 forEach(...) { Self() } 형태로 참조
struct Nested: Reducer {
struct State: Equatable, Identifiable {
let id: UUID
var name: String = ""
var rows: IdentifiedArrayOf<State> = []
}
enum Action: Equatable {
case addRowButtonTapped
case nameTextFieldChanged(String)
case onDelete(IndexSet)
indirect case row(id: State.ID, action: Action)
}
@Dependency(\.uuid) var uuid
var body: some Reducer<State, Action> {
Reduce { state, action in
switch action {
case .addRowButtonTapped:
state.rows.append(State(id: self.uuid()))
return .none
case let .nameTextFieldChanged(name):
state.name = name
return .none
case let .onDelete(indexSet):
state.rows.remove(atOffsets: indexSet)
return .none
case .row:
return .none
}
}
.forEach(\.rows, action: /Action.row(id:action:)) {
Self() // ✅ forEach 부분에 Self() 연결
}
}
}
// MARK: - Feature view
struct NestedView: View {
let store: StoreOf<Nested>
var body: some View {
WithViewStore(self.store, observe: \.name) { viewStore in
Form {
Section {
AboutView(readMe: readMe)
}
// ✅ ForEachStore을 사용하여 배열을 처리!!
ForEachStore(
self.store.scope(state: \.rows, action: Nested.Action.row(id:action:))
) { rowStore in
WithViewStore(rowStore, observe: \.name) { rowViewStore in
NavigationLink(
destination: NestedView(store: rowStore)
) {
HStack {
TextField(
"Untitled",
text: rowViewStore.binding(send: Nested.Action.nameTextFieldChanged)
)
Text("Next")
.font(.callout)
.foregroundStyle(.secondary)
}
}
}
}
.onDelete { viewStore.send(.onDelete($0)) }
}
.navigationTitle(viewStore.state.isEmpty ? "Untitled" : viewStore.state)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("Add row") { viewStore.send(.addRowButtonTapped) }
}
}
}
}
}
extension Nested.State {
static let mock = Nested.State(
id: UUID(),
name: "Foo",
rows: [
Nested.State(
id: UUID(),
name: "Bar",
rows: [
Nested.State(id: UUID(), name: "", rows: [])
]
),
Nested.State(
id: UUID(),
name: "Baz",
rows: [
Nested.State(id: UUID(), name: "Fizz", rows: []),
Nested.State(id: UUID(), name: "Buzz", rows: []),
]
),
Nested.State(id: UUID(), name: "", rows: []),
]
)
}
// MARK: - SwiftUI previews
struct NestedView_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
NestedView(
store: Store(initialState: .mock) {
Nested()
}
)
}
}
}
'apple > TCA' 카테고리의 다른 글
[TCA] HigherOrderReducers #2 (ReusableFavoriting) (1) | 2023.10.29 |
---|---|
[TCA] Navigation (화면전환 총 정리) (0) | 2023.10.09 |
[TCA] Effect #6 (WebSocket) (0) | 2023.10.08 |
[TCA] Effect #5 (Timers) (0) | 2023.10.07 |
[TCA] Effect #4 (Refreshable) (0) | 2023.10.07 |