ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [SwiftUI] 상태관리(Higher-Order Reducers)
    iOS/TCA 2023. 8. 2. 14:17

     

    PointFree 강의 Composable Architecture
    Composable State Management: Higher-Order Reducers 정리

     

     

    📚 이번 강의 목표

    Higher-order reducer에 대해 알아보고 적용해보자 

     

     

     

     


    Higher-order reducer란?

     

    reducer를 input으로 받고, output으로 반환

     

    1. combine

    여러 reducer를 input값으로 받고, 각각 주어진 reducer를 실행하여 새로운 reducer를 output으로 반환하는 함수

     

    2. pullback

    reducer를 input값으로 받고, 로컬 상태와 action에서 작동하는 key path가 주어지면 더 많은 global state와 action에서 작동하는 새로운 reducer를 output으로 반환하는 함수

     

     

     

     

    📚 코드

     

    func activityFeed(
        _ reducer: @escaping (inout AppState, AppAction) -> Void
    ) -> (inout AppState, AppAction) -> Void {
        
        return { state, action in
            switch action {
            case .counter(_):
                break
                
            case .primeModal(.removeFavoritePrimeTapped):
                state.activityFeed.append(.init(timestamp: Date(), type: .removedFavoritePrime(state.count)))
                
            case .primeModal(.saveFavoritePrimeTapped):
                state.activityFeed.append(.init(timestamp: Date(), type: .addedFavoritePrime(state.count)))
                
            case let .favoritePrimes(.deleteFavoritePrimes(indexSet)):
                for index in indexSet {
                    state.activityFeed.append(.init(timestamp: Date(), type: .removedFavoritePrime(state.favoritePrimes[index])))
                }
            }
            reducer(&state, action)
        }
    }

     

    PlaygroundPage.current.liveView = UIHostingController(rootView: ContentView(store: Store(initialValue: AppState(), reducer: activityFeed(appReducer))).frame(width: 392.0, height: 740))

     

    다음과 같이 higher-order reducer 함수를 새로 생성하고, 메인 ContentView 코드를 수정한다.

     

     

     

     

     

    //struct FavoritePrimesState {
    //    var favoritePrimes: [Int]
    //    var activityFeed: [AppState.Activity]
    //}
    
    
    func favoritePrimesReducer(state: inout [Int], action: FavoritePrimesAction) {
        switch action {
        case let .deleteFavoritePrimes(indexSet):
            for index in indexSet {
                state.remove(at: index)
            }
        }
    }

     

    FavoritePrimesState 구조체를 주석 처리하고, favoritePrimesReducer의 state를 [Int]로 변경한다.

     

     

     

     

     

    //extension AppState {
    //    var favoritePrimesState: FavoritePrimesState {
    //        get {
    //            return FavoritePrimesState(favoritePrimes: self.favoritePrimes, activityFeed: self.activityFeed)
    //        }
    //        set {
    //            self.activityFeed = newValue.activityFeed
    //            self.favoritePrimes = newValue.favoritePrimes
    //        }
    //    }
    //}

     

    let _appReducer: (inout AppState, AppAction) -> Void = combine(
        pullback(counterReducer, value: \.count, action: \.counter),
        pullback(primeModalReducer, value: \.self, action: \.primeModal),
        pullback(favoritePrimesReducer, value: \.favoritePrimes, action: \.favoritePrimes)
    )

     

    위의 코드를 주석 처리하고, pullback 함수를 수정해준다.

     

     

     

     

     


    Higher-order logging

    애플리케이션용 logger를 구축하면 사용자가 수행한 모든 작업과 그 결과 상태를 기록할 수 있다.

    디버깅 및 검사에 유용하게 사용할 수 있다.

     

     

    func logging<Value, Action>(
      _ reducer: @escaping (inout Value, Action) -> Void
    ) -> (inout Value, Action) -> Void {
      return { value, action in
        reducer(&value, action)
        print("Action: \(action)")
        print("State:")
        dump(value)
        print("---")
      }
    }
    
    
    final class Store<Value, Action>: ObservableObject {
    // ...
        func send(_ action: Action) {
            self.reducer(&self.value, action)
            print("Action: \(action)")
            print("Value:")
            dump(self.value)
            print("---")
        }
    }

     

     

     

     

     

    'iOS > TCA' 카테고리의 다른 글

    [TCA] TCA 작동 방식  (0) 2023.08.31
    [SwiftUI] 상태관리(Action Pullbacks)  (0) 2023.07.18
    [SwiftUI] 상태관리(State Pullbacks)  (0) 2023.07.07
    [SwiftUI] 상태관리(redux)  (0) 2023.07.06
    [SwiftUI] 상태 관리  (0) 2023.07.05
Designed by Tistory.