์ถ์ฒ ๋ฐ ์ฐธ๊ณ ์ฌ์ดํธ
https://axiomatic-fuschia-666.notion.site/Chapter-3-TCA-2-c56b24efb2154dad9ed8e54139247024
What is Store
- ๋ฐ ํ์๋์ Reducer์ ์ธ์คํด์ค๋ฅผ ๊ด๋ฆฌํ๋ ์ฐธ์กฐ ํ์ ๊ฐ์ฒด
- ์ฑ์ State, Action์ ๊ด๋ฆฌ
- State์ ๋ณํ ๊ฐ์ง
- ์ก์ ์ฒ๋ฆฌ
let store: Store<ProductDetailFeature.State, ProductDetailFeature.Action>
public typealias StoreOf<R: Reducer> = Store<R.State, R.Action>
let store: StoreOf<ProductDetailFeature>
typealias ์ถ์ฝ ํํ
ViewStore๊ฐ ๋ํ๋๊ฒ ๋ ๋ฐฐ๊ฒฝ
- Store: ์ฑ์ ์ํ ๋ณํ ๊ด๋ฆฌ
- ViewStore: View์ ํ์ํ ์ํ๋ง ๊ตฌ๋ ํ๊ณ ์ ๋ฐ์ดํธ
- View์ ํ์ํ์ง ์์ ์ํ์ ๋ณ๊ฒฝ์ผ๋ก ์ธํ ๋ถํ์ํ View ์ ๋ฐ์ดํธ๋ฅผ ๋ฐฉ์ง
- MultiStore
- ์์ View์ Store๋ ํ์ View์ ํ์๋ก ํ๋ ์ํ ์ผ๋ถ๋ฅผ ์์ ํ๊ณ ์๊ณ , ํ์ View์ ์ด ์ผ๋ถ๋ฅผ ์์ ํ๋ ๋ณ๋์ ์คํ ์ด๋ฅผ ์ฐ๊ฒฐํ๊ฒ ํจ
- ์์ View์์ ์ก์ ์ ๋ฐ์ผ๋ฉด ์ด๋ฅผ ๋ถ๋ชจ ์คํ ์ด์ ์ ๋ฌ
- ์ก์ ์ ๋ฐ์ ๋ถ๋ชจ ์คํ ์ด๋ ์์ฒด ๋ฆฌ๋์ ํธ์ถ -> ๋ด๋ถ ์ํ ์ ๋ฐ์ดํธ
- ์ก์ ์ด ์ด๋ฃจ์ด์ง๋ ๋์ ๋ถ๋ชจ ๋ทฐ์ ์์ ๋ทฐ์์ View ๋ ๋๋ง ์์ฒญ์ด ์ค๋ฉด ์ก์ ์ผ๋ก ์ธํ ๋ ๋๋ง ๋ฟ๋ง ์๋๋ผ ์์ ๋ทฐ์ ๋ ๋๋ง ์์ฒญ์ ์ํด ์ฌ๋ฌ๋ฒ ๋ ๋๋ง ํ๋ ์ํฉ์ด ๋ฐ์ ๋จ
- but ViewStore๋ ๋ณํ์ ์ค๋ณต์ ๋ฐฉ์งํ๋ ๊ธฐ๋ฅ์ ํ์ฌ -> View์ ๋ชจ๋ ์ํ๋ฅผ ๊ด์ฐฐ x, ์ผ๋ถ๋ถ์ ๋ณํ๋ก View๋ ๊ทธ ๋ณํ๋ฅผ ๊ฐ์งํ ์ ์์
public init<State>(
_ store: Store<State, ViewAction>,
observe toViewState: @escaping (_ state: State) -> ViewState,
removeDuplicates isDuplicate: @escaping (_ lhs: ViewState, _ rhs: ViewState) -> Bool
) {
self._send = { store.send($0, originatingFrom: nil) }
self._state = CurrentValueRelay(toViewState(store.stateSubject.value))
self._isInvalidated = store._isInvalidated
#if DEBUG
self.storeTypeName = ComposableArchitecture.storeTypeName(of: store)
Logger.shared.log("View\(self.storeTypeName).init")
#endif
self.viewCancellable = store.stateSubject
.map(toViewState)
.removeDuplicates(by: isDuplicate)
.sink { [weak objectWillChange = self.objectWillChange, weak _state = self._state] in
guard let objectWillChange = objectWillChange, let _state = _state else { return }
objectWillChange.send()
_state.value = $0
}
}
- ์ ์ฝ๋์์ @escaping (_ state: State) -> ViewState ์์ View์ ํ์ํ ๋ณํ๋ฅผ ๊ด์ฐฐํ๊ธฐ ์ํด View์ ํ์ํ State struct๋ฅผ ๊ตฌ์ฑ
- ์๋ณธ State๋ฅผ ๊ด์ฐฐํ ์ํ๋ก ๊ตฌ์ฑํ ViewState๋ก ๋ณํ
- ViewState์ ๋ณํ๊ฐ ๊ฐ์ง๋๋ฉด SwiftUI View์๊ฒ ์ํ ๋ณํ๋ฅผ ์๋ฆผ
- isDuplicate๋ก ๋ณํ์ ์ค๋ณต์ ์์ค ๋ค ๋ด๋ถ์ State๊ฐ์ ๊ฐฑ์
WithViewStore
- Reducer ๊ตฌ์ฑ ํ WithViewStore๋ก Store์ View ์ฐ๊ฒฐ
let store: StoreOf<ProductDetailFeature>
var body: some View {
WithViewStore(self.store, observe: { $0 }) { viewStore in
// ๊ธฐ์กด ๋ฐฉ์
}
}
- ๊ธฐ์กด ๋ฐฉ์์ ํ์ ์ ๋ช ์ํด์ ์ปดํ์ผ๋ฌ์ ์ฐ์ฐ์ ์ค์ผ ์ ์์
let store: StoreOf<ProductDetailFeature>
@ObservedObject var viewStore: ViewStoreOf<ProductDetailFeature>
init(store: StoreOf<ProductDetailFeature>) {
self.store = store
self.viewStore = ViewStore(self.store, observe: { $0 })
}
- ์ด๋์ ๋ผ์ด์ ๋ก Store์ ์ฃผ์ ๋ฐ์
- ์ด๋์ ๋ผ์ด์ ๋ด๋ถ์์ ViewStore์ ์์ฑ
- View ๊ณ์ธต ๊ตฌ์กฐ์ ์ ์ด ์ฃผ์๋ WithViewStore ~ ์ ์ค์ผ ์ ์์ด ๊ธฐ์กด ๋ณด๋ค View ๊ณ์ธต์ ์ค์ผ ์ ์์
@dynamicMemberLookup
public final class ViewStore<ViewState, ViewAction>: ObservableObject { /* ... */ }
N.B. `ViewStore` does not use a `@Published` property, so `objectWillChange` won't be synthesized automatically. To work around issues on iOS 13 we explicitly declare it. |
Scope
public func scope<ChildState, ChildAction>(
state toChildState: @escaping (_ state: State) -> ChildState,
action fromChildAction: @escaping (_ childAction: ChildAction) -> Action
) -> Store<ChildState, ChildAction> {
self.scope(state: toChildState, action: fromChildAction, removeDuplicates: nil)
}
- Store์ scope ๋ฉ์๋๋ฅผ ์ด์ฉํด ํ์ State ๋ฐ Action์ ๋ค๋ฃจ๋ ์คํ ์ด๋ก ๋ณํ
- Store์ ์์ ๋ฒ์์ Store๋ก ๋๋ ์ ์์
- ํด๋น ๋๋ฉ์ธ์ ์ํ์ ์ก์ ์ ์ถ์ถํ ์์ ๋ฒ์์ Store์ ๋ฐํ
- ๊ฐ View์ ํ์ํ ์ํ์ ์ก์ ์ ์ ์ํ๊ณ ์ ๊ทผํ ์ ์์
- ๋ชจ๋ํ์ ์ ์ฐ์ฑ
- ์ ๋ ํ ์คํธ ์ฉ์ด
- state: ์ํ๋ฅผ ์ถ์ถํ KeyPath๋ก์ ์์ ๋ทฐ์ state๋ฅผ ์ถ์ถ (WritableKeyPath)
- action: ์ก์ ์ ์ถ์ถํ๊ธฐ ์ํ KeyPath (CasePath)
AmountControlView(
store: self.store.scope(state: \.amountControl, action:
ProductDetailFeature.Action.amountControl)
)
- self.store๋ ์์ ๋ทฐ์ธ ProductDetailFeature์ Store
Scope ๋ ์์๋ณด๊ธฐ
2023.11.30 - [Architecture] - [SwiftUI/TCA] Scope
'iOS ๐ > Architecture' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[SwiftUI/TCA] Binding (0) | 2023.12.07 |
---|---|
[SwiftUI/TCA] Scope (1) | 2023.11.30 |
[SwiftUI/TCA] Effect ๊ตฌํ๊ณผ ํ์ฉ (0) | 2023.11.29 |
[SwiftUI/TCA] Timer ๋ง๋ค๊ธฐ (1) | 2023.11.24 |
[SwiftUI/TCA] TCA ๊ธฐ๋ณธ ๊ฐ๋ ์ ๋ํด ์์๋ณด๊ธฐ (0) | 2023.11.21 |