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
'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 |