새로운 Action 추가 가이드라인

Posted on 2021-10-20 by GKSRUDTN99
Swift&Xcode Xcode Swift RxSwift

새로운 Action 추가 가이드라인

1. Action에 관련된 State 속성을 State 구조체에 추가한다.
struct State {
    var actionView = RevisionedData<ViewAction>(data:nil)
}
2. ViewController의 bind함수에 State를 UI에 바인딩한다.
func bind(reactor: Reactor) {
    reactor.state.map{ $0.actionView }
      .distinctUntilChanged()
      .compactMap{ $0.data }
      .asDriver(onErrorDriveWith: .empty())
      .drive(onNext: { [weak self] view in
        guard let self = self else { return }
        switch view {
        case .pushViewController(let vc):
          self.navigationController?.pushViewController(vc, animated: true)
        case .presentViewController(let vc):
          self.present(vc, animated: false)
        }
      })
      .disposed(by: disposeBag)
}
3. Mutate에 추가한 State를 다룰 수 있는 case를 추가하고, reduce 함수에도 이를 반영한다.
enum Mutation {
  case setView(ViewAction)
}

func reduce(state: State, mutation: Mutation) -> State {
  var newState = state

  switch mutation {
  case .setView(let type):
    newState.actionView = state.actionView.update(type)
  }

  return newState
}
4. UI가 사용할 Action을 case에 추가하고, mutate 함수에 이를 반영한다.
enum Action {
  case showSellerProfile
}

func mutate(action: Action) -> Observable<Mutation> {
  switch action {
  case .showSellerProfile:
    let product = currentState.product
    let vc = AppStoryboard.instantiate(.Common, with: UserProfileViewControllerV2.self)
    vc.userId.accept(product.seller.id)
    vc.partnerId.accept(product.seller.partnerId)
    return .just(.setView(.pushViewController(vc)))
  case .showDetailImages:
    guard let images = currentState.productDescriptionImages else { return .empty() }
    let vc = AppStoryboard.instantiate(.Home, with: ProductDetailImagesViewController.self)
    vc.reactor = ProductDetailImagesViewReactor(images)
    vc.modalPresentationStyle = .overFullScreen
    return .just(.setView(.presentViewController(vc)))

  case .updateCurrentPage(let page):
    return .just(.setCurrentPage(page))
  }
}
5. UI를 Action에 바인딩한다.
func bind(reactor: Reactor) {
  userProfileButton.rx.tap
    .map{ Reactor.Action.showSellerProfile }
    .bind(to: reactor.action)
    .disposed(by: disposeBag)
}