[RxSwift] ReactorKit 알아보기
iOS/RxSwift

[RxSwift] ReactorKit 알아보기

728x90

ReactorKit이란 

반응 및 단방향 Swift 애플리케이션 아키텍처를 위한 프레임워크

RxSwift의 강점인 비동기 처리에 편리한 코드 작성 가능

 

1. View는 Action을 Reactor에게 전달

2. Reactor는 전달받은 Action에 따라 비즈니스 로직을 수행

3. Reactor는 State를 변경하여 View에게 전달

Reactor 내부에서는 2개의 함수로 action을 받아 state를 반환함

 

1. mutate()

- Action이 들어온 경우 어떤 처리를 할지 분기

- Mutation을 reduce 함수로 방출

 

2. reduce()

- 이전 State와 Mutation을 받아서 다음 State를 반환

 

💡 예제

CounterViewReactor

import Foundation
import RxSwift
import RxCocoa
import ReactorKit

class CounterViewReactor: Reactor {
    let initialState = State()
    
    // 사용자 이벤트
    enum Action {
        case increase // 플러스 버튼 누르기
        case decrease // 마이너스 버튼 누르기
    }
    
    // 처리 단위
    enum Mutation {
        case increaseValue // 값 증가
        case decreaseValue // 값 감소
        case setLoading(Bool) // 로딩 setting
    }
    
    // 현재 상태를 기록
    struct State {
        var value = 0 // 몇번 눌렀는지 count
        var isLoading = false // 로딩 여부
    }
}

1. Action

- 사용자 액션 정의

 

2. Mutation 

- 처리 단위, Action과 State의 중간자 역할

 

3. State

- 현재 값을 정의

 

    // Action이 들어온 경우, 어떤 처리를 할건지 분기
    func mutate(action: Action) -> Observable<Mutation> {
        switch action {
        case .increase:
            return Observable.concat([
                Observable.just(.setLoading(true)),
                Observable.just(.increaseValue).delay(.seconds(1), scheduler: MainScheduler.instance),
                Observable.just(.setLoading(false))
            ])
        case .decrease:
            return Observable.concat([
                Observable.just(.setLoading(true)),
                Observable.just(.decreaseValue).delay(.seconds(1), scheduler: MainScheduler.instance),
                Observable.just(.setLoading(false))
            ])
        }
    }
    
    // 이전 상태와 처리 단위를 받아서 다음 상태를 반환하는 함수
    func reduce(state: State, mutation: Mutation) -> State {
        var newState = state
        switch mutation {
        case .increaseValue:
            newState.value += 1
        case .decreaseValue:
            newState.value -= 1
        case .setLoading(let isLoading):
            newState.isLoading = isLoading
        }
        return newState
    }

 

4. mutate()

- Action이 들어온 경우, 어떤 처리를 할건지 분기/비지니스 로직 처리

- reduce()에 State, Mutation 값 전달

 

5. reduce()

- 이전 State와 Mutation를 받아서 다음 State를 반환

 

CounterViewController

import UIKit
import RxSwift
import RxCocoa
import ReactorKit

class CounterViewController: UIViewController, StoryboardView{
    
    var disposeBag = DisposeBag()
    
    @IBOutlet weak var countLabel: UILabel!
    @IBOutlet weak var decreaseButton: UIButton!
    @IBOutlet weak var increaseButton: UIButton!
    @IBOutlet weak var activityIndicatorView: UIActivityIndicatorView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
    }
    
    // 인터렉션을 Reactor에서 정의한 값으로 매핑
    func bind(reactor: CounterViewReactor) {
        bindAction(reactor)
        bindState(reactor)
    }
    
    // action 바인딩
    private func bindAction(_ reactor: CounterViewReactor) {
        increaseButton.rx.tap
            .map { Reactor.Action.increase}
            .bind(to: reactor.action)
            .disposed(by: disposeBag)
        
        decreaseButton.rx.tap
            .map { Reactor.Action.decrease }
            .bind(to: reactor.action)
            .disposed(by: disposeBag)
    }
    
    // state 바인딩
    private func bindState(_ reactor: CounterViewReactor) {
        reactor.state
            .map { String($0.value) }
            .distinctUntilChanged()
            .bind(to: countLabel.rx.text)
            .disposed(by: disposeBag)
        
        reactor.state
            .map { $0.isLoading }
            .distinctUntilChanged()
            .bind(to: activityIndicatorView.rx.isAnimating)
            .disposed(by: disposeBag)
    }
}

1. Action 바인딩

- 사용자 이벤트 연결

 

2. State 바인딩 

- 변화된 State 값 View에 반영

 

✨ storyboard 지원을 위해 StoryboardView 프로토콜을 따라야함

 

실행 영상

 

참고

https://github.com/ReactorKit/ReactorKit

https://medium.com/styleshare/reactorkit-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-c7b52fbb131a

https://ios-development.tistory.com/782

728x90

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

[RxSwift] Network 통신하기  (0) 2022.11.15
[RxSwift] UITextField에 Rx 적용하기  (0) 2022.11.01
[RxSwift] RxCocoa란?  (0) 2022.10.23
[RxSwift] Combining Operator 알아보기  (0) 2022.10.23
[RxSwift] Transforming Operator 알아보기  (0) 2022.10.23