์ฐธ๊ณ ์ฌ์ดํธ
https://axiomatic-fuschia-666.notion.site/Chapter-1-Hello-TCA-70c56437681547d4b85cd1363a157356
์ฐธ๊ณ ์ฌ์ดํธ ๋ถํฐ ์ ๋ ์ด์ ๋ TCA๋ฅผ ๋ฐฐ์ฐ๊ธฐ ๊ฐ์ฅ ์ข์ ์ฌ์ดํธ๋ ์๋ฌด๋๋ TCA๋ฅผ ๋ง๋ pointfree์ ์ด๋ฅผ ํ ๋๋ก ๋ง๋ ์ ์์ฑ ์ด์ง ์์๊น ์ถ์ต๋๋ค!
ViewModel
- ๊ธฐ์กด UIKit์์์ ViewModel
- RxSwift + ViewModel => ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ์ ์ฑ ์์ง. Reactive Programing
- SwiftUI์์์ ViewModel
- SwiftUI์์๋ View ๋ ๋ฒจ์์ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ํ ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ ๊ฐ๋ฅ
- ViewModel์ด ์ํํ๋ ์ผ์ View๊ฐ ์ฒ๋ฆฌํ ์ ์๊ฒ ๋จ
TCA์ ํน์ง
- ๊ฐ ํ์ ๊ธฐ๋ฐ
- ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฒด ์ํ๋ฅผ ์ผ๊ด์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์๋ ํ์ค ์ ์
- ์ต์ ๊ธฐ๋ฅ ๋จ์ -> ๊ฐ์ฒด ๊ฐ ๊ฒฐํฉ ๋ฐ ๋ถ๋ฆฌ, ์ฌ์ฌ์ฉ์ฑ ์ฌ์์ง
- ํ ์คํธ ์ ์ฐ์ฑ ํ๋ณด
SwiftUI์์์ MVVM
- SwiftUI๋ ์๋ฐฉํฅ ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ์ ์ง์ํ๋ ํ๋ ์์ํฌ
- View๊ฐ ViewModel์ ์์ฒญ์ ๋ฐ์์จ ํ ์ถ๊ฐ ์์ ์ด ํ์ํ ๊ฒฝ์ฐ๊ฐ ๋ฐ์
Reducer ์์ฑ
struct ProductDetailFeature: Reducer {
struct State: Equatable {
// ์๋ต
}
enum Action: Equatable {
// ์๋ต
}
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
// ์๋ต
}
}
}
}
- State, Action, body property(ํน์ reduce(into:action:) ํจ์)๋ฅผ ๊ตฌํํด์ผ ํจ
- ์ฃผ์ด์ง Action์ ๋ฐํ์ผ๋ก ํ์ฌ State๋ฅผ ์ด๋ป๊ฒ ๋ค์ ์ํ๋ก ๋ฐ๊ฟ ๊ฒ์ธ์ง ์ ์
View์ Reducer ์ฐ๊ฒฐ
struct ProductDetailView: View {
let store: StoreOf<ProductDetailFeature>
var body: some View {
WithViewStore(self.store, observe: { $0 }) { viewStore in
// ์๋ต
}
}
}
- StoreOf<ProductDetailFeature>์ ์ด์ ๋ฐฉ์์ Store<ProductDetailFeature.State, ProductDetailFeature.Action>
State
struct State: Equatable {
let productId = 4
var product: Product?
var isLike: Bool = false
}
- View์ ํ์ํ ์ํ๊ฐ์ด๋ฉฐ ํ์ฌ ์ํ๋ฅผ ๊ฐ์ง๋ ๊ตฌ์กฐ์ฒด
- ์ด ์ํ๊ฐ์ด ๋ณ๊ฒฝ๋๋ฉด ์ด๋ฅผ View์ ๋ฐ์
- ๊ฐํ์
- ๋ณ๋์ ์ถ์ ํ๊ณ ์๋ํ์ง ์์ ๋ณ๊ฒฝ์์ ์ง์ผ๋ด์ผ ํ ์ํ
- Single Source Of Truth
Action
enum Action: Equatable {
case likeButtonTapped
case productResponse(Product)
case getProductDetail
}
- ์ฌ์ฉ์ ์ธํฐ๋ ์ ์ ๋ฐ์์ค๊ธฐ ์ํ ํ์
- ์ฌ์ฉ์๊ฐ View๋ฅผ ํตํด ์ด๋ค ์์ ์ด๋ ์๋ฆผ, ์ด๋ฒคํธ๋ฅผ ์ ์
- Action์ ๋ค์ด๋ฐ ํ ๋์๋ ์ฌ์ฉ์๊ฐ UI์์ ์ํํ ์์ ์ ์ด๋ฆ์ ๋ฐ์ ์ง๋ ๊ฒ์ด ์ถ์ฒ๋จ
Effect
var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .likeButtonTapped:
state.isLike.toggle()
return .none
case .productResponse(let product):
state.product = product
return .none
case .getProductDetail:
return .run { [id = state.productId] send in
let (data, _) = try await URLSession.shared.data(from: URL(string: "https://api/v1/products/\(id)")!)
do {
let product = try JSONDecoder().decode(Product.self, from: data)
print(product)
await send(.productResponse(product))
} catch {
// TODO: error handling
}
}
}
}
}
- Action์ด State๋ฅผ ๋ณํ์ํค๋ Effect๋ฅผ ๋ฐํ
- ์ํ๋ฅผ ๋ณํ์ํค๊ฑฐ๋ ๋คํธ์ํฌ ํต์ ๊ฐ์ ๋น๋๊ธฐ ์์ ์ ์ํํจ
- body ์์ฑ์ ์ฌ์ฉํ๋ฉด ์ง์ ์ํ ๋ณ๊ฒฝ ๋๋ ํจ๊ณผ ๋ก์ง์ ์ํํ์ง ์์
- body ์์ฑ์ ๋ฐํ ๊ฐ์ด some Reducer์ธ opaque type์ด๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ๋ฆฌ๋์์ ์กฐํฉํ ์ ์์
- ์ฑ์ ๋ณต์ก๋๊ฐ ์ฆ๊ฐํ์ ๋ ์ฉ์ด
- ์์ ๋จ์์ ๋ฆฌ๋์๋ก ๊ตฌํํ ๋ ์ฉ์ด
func reduce(into state: inout State, action: Action) -> Effect<Action> {
switch action {
// ์๋ต
}
}
- ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ
- ๋ฆฌ๋์์ ๋ก์ง์ ์ง์ ๋ฉ์๋ ๋ด๋ถ์ ๊ตฌํ
- ๋ค๋ฅธ ๋ฆฌ๋์์์ ๊ฒฐํฉ์ด ํ์ ์๋ ๊ฒฝ์ฐ์ ์ฌ์ฉ
Equatable
- WithViewStore์ ์ด๋์ ๋ผ์ด์ ์์ State๊ฐ Equatable ํ๋กํ ์ฝ์ ์ค์ํ๋๋ก ์๊ตฌ
- ์ํ ๋ณํ๋ฅผ ๊ฐ์งํ๊ธฐ ์ํด ์ด์ ์ํ์ ํ์ฌ ์ํ๋ฅผ ๋น๊ตํ๊ฒ ๋จ. ์ด ๊ณผ์ ์ ํตํด ๋ถํ์ํ ๋ ๋๋ง์ ๋ฐฉ์งํ ์ ์์
- ๋ง์ฝ ์ฐธ์กฐ ํ์ ์ State์ ๊ฒฝ์ฐ ๊ฐ์ฒด ๋ด๋ถ์ ๊ฐ์ด ๋ณ๊ฒฝ๋๋ฉด ์ด ๋ณ๊ฒฝ์ ์ ์ ์๊ธฐ ๋๋ฌธ์ ๋ณํ๋ฅผ ์ธ์งํ์ง ๋ชปํ ์ ์์
struct Product: Codable, Identifiable, Equatable {
let id: Int
let title: String
let price: Int
let description: String
let images: [String]
let creationAt, updatedAt: String
let category: Category
static func == (lhs: Product, rhs: Product) -> Bool {
lhs.id == rhs.id
}
}
- State์ ๋ณํ๋ฅผ ์๊ธฐ ์ํด Equatable์ ์ค์ํด์ผ ํ๋ค.
- ์ํ ๊ด๋ฆฌ๋ฅผ ๊ฐ์ํํ๊ณ ๋ฒ๊ทธ๋ฅผ ์ค์ด๋ ๋ฐฉ์
Effect & Side Effect
- ์์
์ ๋ํ ๊ฒฐ๊ณผ๋ฅผ ์๋ฏธ
- ์์ ์ ์ฑ๊ณตํ ๊ฒฝ์ฐ Effect
- ์์ ์ด ์์์น ๋ชปํ ์คํจ๋ฅผ ํ๋ ๊ฒฝ์ฐ Side Effect
- effect์ side effect์ ๋ฐ๋ผ ๋ค์ Action์ ์ ํํด Sate๋ฅผ ๋ณ๊ฒฝํ๊ณ ์ด State๋ ๋ค์ ๋ทฐ์ ์ํฅ์ ์ฃผ๊ฒ ๋๋ ๋จ๋ฐฉํฅ ํ๋ฆ์ ๊ฐ์ง
'iOS ๐ > Architecture' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[SwiftUI/TCA] Binding (0) | 2023.12.07 |
---|---|
[SwiftUI/TCA] Scope (1) | 2023.11.30 |
[SwiftUI/TCA] Store and ViewStore (0) | 2023.11.29 |
[SwiftUI/TCA] Effect ๊ตฌํ๊ณผ ํ์ฉ (0) | 2023.11.29 |
[SwiftUI/TCA] Timer ๋ง๋ค๊ธฐ (1) | 2023.11.24 |