[TCA] Effect #4 (Refreshable)
목차
- Refreshable에 대한
- Refreshable을 사용하는 예제
# Refreshable에 대한
이번에는 List를 리프레시 하는 방법에 대해서 알아보자
이번에는 버튼을 클릭해서 API 콜하는게 아니라 리프레시를 통해 API를 콜 할 예정이다.
특이점으로는 viewStore.send(..., animation: ) 으로 animation을 건네주어 볼 예정!
# Refreshable을 사용하는 예제
// MARK: - Feature domain
struct Refreshable: Reducer {
struct State: Equatable {
var count = 0
var fact: String?
}
enum Action: Equatable {
case cancelButtonTapped
case decrementButtonTapped
case factResponse(TaskResult<String>)
case incrementButtonTapped
case refresh
}
@Dependency(\.factClient) var factClient
private enum CancelID { case factRequest }
func reduce(into state: inout State, action: Action) -> Effect<Action> {
switch action {
case .cancelButtonTapped:
return .cancel(id: CancelID.factRequest)
case .decrementButtonTapped:
state.count -= 1
return .none
case let .factResponse(.success(fact)):
state.fact = fact
return .none
case .factResponse(.failure):
// 여기서 에러 핸들링!
return .none
case .incrementButtonTapped:
state.count += 1
return .none
case .refresh:
state.fact = nil
return .run { [count = state.count] send in
await send(
.factResponse(TaskResult { try await self.factClient.fetch(count) }), // API 콜!
animation: .default // 애니메이션 지정 가능
)
}
.cancellable(id: CancelID.factRequest)
}
}
}
// MARK: - Feature view
struct RefreshableView: View {
@State var isLoading = false
let store: StoreOf<Refreshable>
var body: some View {
WithViewStore(self.store, observe: { $0 }) { viewStore in
List {
Section {
AboutView(readMe: readMe)
}
HStack {
Button {
viewStore.send(.decrementButtonTapped)
} label: {
Image(systemName: "minus")
}
Text("\(viewStore.count)")
.monospacedDigit()
Button {
viewStore.send(.incrementButtonTapped)
} label: {
Image(systemName: "plus")
}
}
.frame(maxWidth: .infinity)
.buttonStyle(.borderless)
if let fact = viewStore.fact {
Text(fact)
.bold()
}
if self.isLoading {
Button("Cancel") {
viewStore.send(.cancelButtonTapped, animation: .default) // 애니메이션을 옵션으로 건네줄 수 있음.
}
}
}
.refreshable {
self.isLoading = true
defer { self.isLoading = false }
await viewStore.send(.refresh).finish()
}
}
}
}
// MARK: - SwiftUI previews
struct Refreshable_Previews: PreviewProvider {
static var previews: some View {
RefreshableView(
store: Store(initialState: Refreshable.State()) {
Refreshable()
}
)
}
}
애니메이션이 없으면 UI가 뚝 끊기듯이 나타난다!!
애니메이션을 통해 더 나은 UX를 제공할 수 있을 거 같다!
비동기 send를 처리해야 하는 경우 finish를 사용해야 한다.
그렇지 않을 경우 바인딩 중첩 문제가 발생하는데, 자세한 부분은 한번 싹 공부하고나서 다시 보도록 하자!
'apple > TCA' 카테고리의 다른 글
[TCA] Effect #6 (WebSocket) (0) | 2023.10.08 |
---|---|
[TCA] Effect #5 (Timers) (0) | 2023.10.07 |
[TCA] Effect #3 (LongLiving) (0) | 2023.10.07 |
[TCA] Effect #2 (Cancellation) (0) | 2023.10.07 |
[TCA] Effect #1 (Basics) (1) | 2023.10.07 |