[SwiftUI] μνκ΄λ¦¬(redux)
PointFree κ°μ Composable Architecture
Composable State Management: Reducers μ 리
π μ΄λ² κ°μ λͺ©ν
μ λ² κ²μκΈμμ μμ±ν μ½λμμ
1. CombineμΌλ‘λΆν° λΆλ¦¬
2. κ° νμ μ μ΄μ νμ©
μ μν΄ μν λ³νλ₯Ό κ°μ§νλ κ°μ²΄λ₯Ό λ§λ€κ³ μ νλ€!
π μ½λ
struct AppState {
var count = 0
var favoritePrimes: [Int] = []
var loggedInUser: User?
var activityFeed: [Activity] = []
var didChange = PassthroughSubject<Void, Never>()
struct Activity {
let timestamp: Date
let type: ActivityType
enum ActivityType {
case addedFavoritePrime(Int)
case removedFavoritePrime(Int)
}
}
struct User {
let id: Int
let name: String
let bio: String
}
}
κΈ°μ‘΄ class νμ μ AppState μ½λλ₯Ό κ΅¬μ‘°μ²΄λ‘ λ³κ²½νλ€. μ΄λ¬λ©΄ λμ΄μ @Publishedλ‘ λ³μλ₯Ό μ μΈνμ§ μμλ λλ€.
μ¬κΈ°μ ObservableObjectλ₯Ό μ€μνκΈ° μν΄μ ꡬ쑰체λ₯Ό κ°μΈλ ν΄λμ€λ₯Ό μλ‘ μ μΈν΄μΌν¨(Store)
final class Store<Value, Action>: ObservableObject {
let reducer: (inout Value, Action) -> Void
@Published var value: Value
init(initialValue: Value, reducer: @escaping (inout Value, Action) -> Void) {
self.value = initialValue
self.reducer = reducer
}
func send(_ action: Action) {
self.reducer(&self.value, action)
}
}
AppStateμ λ³νλ₯Ό κ°μ§νλ Store<AppState> κ°μ²΄λ₯Ό μμ±νκΈ° μν ν΄λμ€λ₯Ό μ μνλ€.
Store ν΄λμ€μ μν : κ° μ νμ λνν΄μ κ΄μ°°μμκ² ν μ 곡
AppStateμ λν΄μλ μ νμκ° μκΈ° λλ¬Έμ μ λ€λ¦ νμ μΌλ‘ μ μΈ
// μ¬μ©μ μ‘μ
νμ
μ§μ
enum CounterAction {
case decrementTapped
case incrementTapped
}
enum PrimeModalAction {
case saveFavoritePrimeTapped
case removeFavoritePrimeTapped
}
enum FavoritePrimesAction {
case deleteFavoritePrimes(IndexSet)
}
enum AppAction {
case counter(CounterAction)
case primeModal(PrimeModalAction)
case favoritePrimes(FavoritePrimesAction)
}
func appReducer(state: inout AppState, action: AppAction) -> Void {
switch action {
case .counter(.decrementTapped):
state.count -= 1
case .counter(.incrementTapped):
state.count += 1
case .primeModal(.saveFavoritePrimeTapped):
state.favoritePrimes.append(state.count)
state.activityFeed.append(.init(timestamp: Date(), type: .addedFavoritePrime(state.count)))
case .primeModal(.removeFavoritePrimeTapped):
state.favoritePrimes.removeAll(where: { $0 == state.count })
state.activityFeed.append(.init(timestamp: Date(), type: .removedFavoritePrime(state.count)))
case let .favoritePrimes(.deleteFavoritePrimes(indexSet)):
for index in indexSet {
let prime = state.favoritePrimes[index]
state.favoritePrimes.remove(at: index)
state.activityFeed.append(.init(timestamp: Date(), type: .removedFavoritePrime(prime)))
}
}
}
μ¬μ©μ μ‘μ νμ κ³Ό κ·Έμ λ°λ₯Έ μ‘μ μ μ μνλ€
@ObservedObject var store: Store<AppState, AppAction>
ObservedObject λ³μλ₯Ό λ€μκ³Ό κ°μ΄ λ³κ²½ν΄μ€λ€
μν λ³νμ λ°λ₯Έ νλμ reducerμ 격리ν΄μ storeμμ send() λ©μλ νΈμΆμ ν΅ν΄ ν μ μλλ‘ νλ€.