Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- dispatchqueue
- c++
- spritekit
- 웹
- 리액트
- 알고리즘
- Protocol
- widget
- 스위프트
- widgetkit
- 스유
- Swift
- 운영체제
- 대외활동
- swift concurrency
- SwiftUI
- uikit
- composable architecture
- 후기
- 1일1알골
- TCA
- 백준
- 컴퓨터그래픽스
- 위젯킷
- 멋사
- 영남대
- cs
- 네트워크
- 멋쟁이사자처럼
- 문법
Archives
- Today
- Total
맛동산이
SwiftUI) TCA - Navigation하는 방법(Presents, PresentationAction, ifLet) 본문
앱/SwiftUI
SwiftUI) TCA - Navigation하는 방법(Presents, PresentationAction, ifLet)
진ddang 2024. 9. 17. 04:47두개의 reducer와 state그리고 화면을 이동하는 방법을 사용할때는
- @Presents
- PresentationAction
- ifLet
을 사용하게 된다.
1. 먼저 가고자 하는 뷰의 State를 @Presents로 감싼다.
또한 네이게이션 stack이 될 array을 생성한다. (보편적으로 스택의 경우에는 최상단의 뷰가 가지면 된다.)
밑의 코드에서는 concats가 stack이 될 array
@ObservableState
struct State: Equatable {
@Presents var addContact: AddContactFeature.State?
var contacts: IdentifiedArrayOf<Contact> = []
}
해당 뷰로 이동할지 안할지 모르니까 옵셔널 값.
2. 해당 뷰로 이동하는 액션을 정의( PresentationAction )
case addContact(PresentationAction<AddContactFeature.Action>)
3. ifLet을 통해서 해당 뷰의 값을 받도록 한다.
리듀서에서 .ifLet값을 통해서 리듀서를 받도록 하며
.ifLet(\\.$addContact, action: \\.addContact) {
AddContactFeature()
}
4. 하위뷰에서의 액션을 받을때
case .addContact(.presented(.saveButtonTapped)):
guard let contact = state.addContact?.contact
else { return .none }
state.contacts.append(contact)
state.addContact = nil
return .none
실제로 .presented상태일때 해당 뷰에서 .saveButtonTapped가 날라오면, 다음과 같은 액션을 취하도록 하는 effect 코드이다.
5. 뷰 연결해주기
struct ContactsView: View {
@Bindable var store: StoreOf<ContactsFeature>
var body: some View {
NavigationStack {
List {
ForEach(store.contacts) { contact in
Text(contact.name)
}
}
.navigationTitle("Contacts")
.toolbar {
ToolbarItem {
Button {
store.send(.addButtonTapped)
} label: {
Image(systemName: "plus")
}
}
}
}
.sheet(
item: $store.scope(state: \\.addContact, action: \\.addContact)
) { addContactStore in
NavigationStack {
AddContactView(store: addContactStore)
}
}
}
}
Bindable을 통해서 해당 값이 바인딩 될수 있도록 변경해주고,
scop을 사용해서 해당 state안의 만들어진 AddContactFeature.State? 를 해당 뷰에 주입해준다.
하위 뷰에서 상위뷰로의 액션을 전달해주는 방법
하위뷰에서 상위뷰로 액션을 전달해주고 싶을때는 동일하게 delegate를 사용하지만 이역시 action에서 정의해서 내려줘야한다.
방법은 다음과 같다 .
1. delegate액션과 enum을 정의한다.
struct AddContactFeature {
@ObservableState
struct State: Equatable {
var contact: Contact
}
enum Action {
case cancelButtonTapped
case delegate(Delegate)
case saveButtonTapped
case setName(String)
enum Delegate: Equatable {
case cancel
case saveContact(Contact)
}
}
위에서 Delegate가 상위 액션으로 전달될 delegate액션
2. 액션에서 호출 해준다.
Reduce { state, action in
switch action {
case .cancelButtonTapped:
return .send(.delegate(.cancel))
case .delegate:
return .none
case .saveButtonTapped:
return .send(.delegate(.saveContact(state.contact)))
이때 해당 뷰의 dismiss를 하기 위해서는 다음과 같은 액션으로 처리하면 된다.
case .cancelButtonTapped:
return .run { _ in await self.dismiss() }
혹은 어떠한 액션을 취하고 난뒤라면
case .saveButtonTapped:
return .run { [contact = state.contact] send in
await send(.delegate(.saveContact(contact)))
await self.dismiss()
}
3. 상위 PresentationAction에서 정의된 액션에서 해당 액션을 받아서 처리한다.
enum Action {
case addButtonTapped
case addContact(PresentationAction<AddContactFeature.Action>)
}
case .addContact(.presented(.delegate(.cancel))):
state.addContact = nil
return .none
case let .addContact(.presented(.delegate(.saveContact(contact)))):
// guard let contact = state.addContact?.contact
// else { return .none }
또는
.navigationDestination(
store: store.scope(state: \.$destination.personsList, action: \.destination.personsList)
) {
PersonsListView(store: $0)
}
이렇게 navigationDestination으로 네비게이션 할수 잇는 방법도 있음.
반응형
'앱 > SwiftUI' 카테고리의 다른 글
SwiftUI) TCA- Effect에 대해서 (0) | 2024.09.17 |
---|---|
SwiftUI) TAC - NestedAction, Action의 가독성을 높이기 위한 방법 (2) | 2024.09.17 |
SwiftUI) TAC 에서 공유 데이터 사용하는법(shared Data), AsyncStream과 Shared State (0) | 2024.09.17 |
SwiftUI) TCA - ifLet, 옵셔널 State를 언래핑하는법 - 화면전환이 필요할때 (0) | 2024.09.17 |
SwiftUI) TCA 비동기처리, TaskResult타입 (0) | 2024.08.08 |