-
[TCA] Sharing logic with actionsTCA 2023. 8. 14. 10:57
μ‘μ μ μ¬μ©νμ¬ λ¦¬λμμ μ¬λ¬ λΆλΆμμ λ‘μ§μ 곡μ νλ μΌλ°μ μΈ ν¨ν΄μ΄ μλλ°, μ΄λ λΉν¨μ¨μ μΈ ν¨ν΄μ΄λ€.
μ‘μ μ μ μ‘νλ κ²μ ν΄λμ€μμ λ©μλλ₯Ό νΈμΆνλ κ²λ§νΌ κ°λ²Όμ΄ μμ μ΄ μλκΈ° λλ¬Έμ΄λ€. μ‘μ μ μ ν리μΌμ΄μ μ μ¬λ¬ λ μ΄μ΄λ₯Ό ν΅κ³Όνλ©° κ° λ μ΄μ΄λ§λ€ 리λμκ° μ‘μ μ κ°λ‘μ±κ³ μ¬ν΄μν μ μλ€.
λμ , Reducerλ₯Ό μ€μνλ©΄μ κ°λ¨ν λ©μλλ₯Ό μ¬μ©νμ¬ λ‘μ§μ 곡μ νλ κ²μ΄ ν¨μ¬ λ μ’μ λ°©λ²μ΄λ€. μ΄ λ©μλλ λ³μ΄λ₯Ό ν΄μΌν κ²½μ°, Stateλ₯Ό inout μΈμλ‘ λ°μμ μ¬μ©ν μ μκ³ , Effect<Action>μ λ°νν μ μλ€. μ΄λ₯Ό ν΅ν΄ λΆνμν μ‘μ μ μ μ‘νλ λΉμ©μ λ°μμν€μ§ μκ³ λ‘μ§μ 곡μ ν μ μλ€.
μλ₯Ό λ€μ΄, νΌμ³μ 3κ°μ UI μ»΄ν¬λνΈκ° μκ³ μ΄λ€ μ»΄ν¬λνΈκ° λ³κ²½λλ©΄ ν΄λΉ μν νλλ₯Ό μ λ°μ΄νΈνκ³ , λ³μ΄λ₯Ό μννμ¬ μ΄ννΈλ₯Ό μ€ννλ €κ³ νλ€κ³ κ°μ ν΄λ³΄μ. μ΄λ¬ν 곡ν΅λ λ³μ΄μ μ΄ννΈλ₯Ό λ³λμ μ‘μ μΌλ‘ μ μνκ³ κ° μ¬μ©μ μ‘μ μ ν΄λΉ 곡μ μ‘μ μ μ¦μ μ€ννλ μ΄ννΈλ₯Ό λ°νν μ μλ€.
struct Feature: Reducer { struct State { // ... } enum Action { // ... } func reduce(into state: inout State, action: Action) -> Effect<Action> { switch action { case .buttonTapped: state.count += 1 return .send(.sharedComputation) case .toggleChanged: state.isEnabled.toggle() return .send(.sharedComputation) case let .textFieldChanged(text): state.description = text return .send(.sharedComputation) case .sharedComputation: // Some shared work to compute something. return .run { send in // A shared effect to compute something } } } }μ΄λ λ‘μ§κ³Ό μ΄ννΈλ₯Ό 곡μ νλ λ°©λ²μ΄μ§λ§, μ¬μ©μκ° νλμ μ‘μ μ μννμμλ λΆκ΅¬νκ³ 2κ°μ μ‘μ μ λν λΉμ©μ΄ λ°μνκ³ μμΌλ―λ‘ λΉν¨μ¨μ μ΄λ€.
μ΄λ¬ν μ±λ₯ λ¬Έμ μΈμλ μ΄ ν¨ν΄μ λ°λ₯΄μ§ μμμΌ νλ 2κ°μ§ μ΄μ κ° μλ€.
첫째, μ΄λ° νμμ λ‘μ§ κ³΅μ λ°©μμ μ μ°μ±μ΄ λΆμ‘±νλ€. 곡μ λ‘μ§μ΄ λ³λμ μ‘μ μΌλ‘ λΆλ¦¬λκΈ° λλ¬Έμ νμ μ΄κΈ° λ‘μ§ μ΄νμ μ€νλμ΄μΌ νλ€. νμ§λ§ μ΄κΈ° λ‘μ§ μ€ν μ μ μΌλΆ 곡μ λ‘μ§μ μ€νν΄μΌ ν κ²½μ° μ΄λ»κ² ν΄μΌν κΉ? μ΄λ° κ²½μ°μλ μ΄ ν¨ν΄μ μ μ©νκΈ° μ΄λ ΅λ€.
λμ§Έ, μ΄λ° νμμ λ‘μ§ κ³΅μ λ°©μμ ν μ€νΈλ₯Ό μ΄λ ΅κ² λ§λ λ€. μ¬μ©μ μ‘μ μ μ μ‘ν λ 곡μ μ‘μ μ μμ νκ³ μν λ³κ²½μ νμΈν΄μΌ νλ€. μ΄λ κ² νλ©΄ ν μ€νΈκ° λΆνμν λ΄λΆ μΈλΆμ¬νμΌλ‘ ν½μ°½λκ³ , ν μ€νΈκ° μ¬μ©μκ° κΈ°λ₯μ μ΄λ»κ² μ¬μ©νλμ§μ λν λͺ νν μ€ν¬λ¦½νΈλ‘ μ½νμ§ μκ² λλ€.
let store = TestStore(initialState: Feature.State()) { Feature() } store.send(.buttonTapped) { $0.count = 1 } store.receive(.sharedComputation) { // Assert on shared logic } store.send(.toggleChanged) { $0.isEnabled = true } store.receive(.sharedComputation) { // Assert on shared logic } store.send(.textFieldChanged("Hello") { $0.description = "Hello" } store.receive(.sharedComputation) { // Assert on shared logic }λ°λΌμ 리λμ λ΄μμ μ μ© μ‘μ μ μ¬μ©νμ¬ λκΈ°μ μ΄ννΈλ₯Ό μ€ννλ λ°©μμΌλ‘ λ‘μ§μ 곡μ νλ ν¨ν΄μ μΆμ²νμ§ μλλ€.
λμ , νΌμ³μ 리λμμ μ μλ λ©μλλ‘ λ‘μ§μ 곡μ νλ κ²μ μΆμ²νλ€. μ΄ λ©μλλ λͺ¨λ μ’ μμ±μ λν μ 체 μ‘μΈμ€ κΆνμ κ°κ³ , μνλ₯Ό λ³κ²½ν΄μΌ νλ κ²½μ° inout Stateλ₯Ό μ·¨νκ³ , μ΄ννΈλ₯Ό μ€νν΄μΌ ν κ²½μ° Effect<Action>μ λ°νν μ μλ€.
μμ μμ λ λ€μκ³Ό κ°μ΄ 리ν©ν°λ§ν μ μλ€.
struct Feature: Reducer { struct State { // ... } enum Action { // ... } func reduce(into state: inout State, action: Action) -> Effect<Action> { switch action { case .buttonTapped: state.count += 1 return self.sharedComputation(state: &state) case .toggleChanged: state.isEnabled.toggle() return self.sharedComputation(state: &state) case let .textFieldChanged(text): state.description = text return self.sharedComputation(state: &state) } } func sharedComputation(state: inout State) -> Effect<Action> { // Some shared work to compute something. return .run { send in // A shared effect to compute something } } }μ΄ λ°©μμ μ΄μ κ³Ό λμΌνκ² λμνμ§λ§, μ¬μ©μ μ‘μ μ΄ μ μ‘λ λ λͺ¨λ λ‘μ§μ΄ μΆκ°μ μΈ μ‘μ μ 보λ΄μ§ μκ³ ν λ²μ μ€νλλ€. λν μμμ μΈκΈν λ€λ₯Έ λ¬Έμ λ€λ ν΄κ²°νλ€.
μλ₯Ό λ€μ΄ ν΅μ¬ λ‘μ§λ³΄λ€ 곡μ λ‘μ§μ λ¨Όμ μ€νν΄μΌ νλ κ²½μ°, λ€μκ³Ό κ°μ΄ μ€νν μ μλ€.
case .buttonTapped: let sharedEffect = self.sharedComputation(state: &state) state.count += 1 return sharedEffectμ΄λ° μμΌλ‘ 곡μ λ‘μ§μ μΈμ , μ΄λ»κ², μ΄λμ μ€νν μ§λ₯Ό μ μ°νκ² κ²°μ ν μ μλ€.
λν μ μ‘λλ 곡μ μ‘μ μ μΆκ° λ΄λΆ μΈνμ νμΈν νμκ° μμΌλ―λ‘ ν μ€νΈκ° λ κ°λ¨ν΄μ§λ€. ν μ€νΈλ μ¬μ©μκ° κΈ°λ₯μμ 무μμ μννλμ§μ λν μ€ν¬λ¦½νΈμ²λΌ μ½νκ² λλ€.
let store = TestStore(initialState: Feature.State()) { Feature() } store.send(.buttonTapped) { $0.count = 1 // Assert on shared logic } store.send(.toggleChanged) { $0.isEnabled = true // Assert on shared logic } store.send(.textFieldChanged("Hello") { $0.description = "Hello" // Assert on shared logic }μλ¬Έ