概要
ReactorKitを使ったプロジェクトでFirestoreを使うことになったので、Pringを用いて実装しました。
環境
- Xcode 11.0
- Swift 5.1
- ReactorKit 1.2.1 (https://github.com/ReactorKit/ReactorKit)
- Pring 0.17.3 (https://github.com/1amageek/Pring)
実装
UserというモデルをFirestoreから取得してくるという設定です。
Reactor側
Action, Mutation, State, mutate, reduceはやるだけって感じです。
ポイントはdataSourceを以下のように用意して、
private let dataSource: DataSource<User>?
setupDataSource()内でDataSourceをlisten()してやることです。
この時.onの中でself?.action.onNext(.updateUsers(users))することで、Firestoreから取得したデータをReactorのストリームにうまく取り込んでます。
private func setupDataSource() {
dataSource = User.query.dataSource()
.on { [weak self] _, _ in
guard let users = self?.dataSource?.documents else { return }
self?.action.onNext(.updateUsers(users))
}
.listen()
}
全実装は以下のようになります。
import ReactorKit
import RxSwift
import Pring
final class UserListReactor: Reactor {
enum Action {
case updateUsers([User])
}
enum Mutation {
case setUsers([User])
}
struct State {
var users: [User] = []
}
// MARK: - Variables
let initialState = State()
private let dataSource: DataSource<User>?
// MARK: - Initializer
init() {
setupDataSource()
}
// MARK: - Setup Methods
private func setupDataSource() {
dataSource = User.query.dataSource()
.on { [weak self] _, _ in
guard let users = self?.dataSource?.documents else { return }
self?.action.onNext(.updateUsers(users))
}
.listen()
}
// MARK: - Reactor Methods
func mutate(action: Action) -> Observable<Mutation> {
switch action {
case let .updateUsers(users):
return .just(Mutation.setUsers(users))
}
}
func reduce(state: State, mutation: Mutation) -> State {
var state = state
switch mutation {
case let .setUsers(users):
state.users = users
}
return state
}
}
ViewController側
いつも通りbind(reactor:)内でUserListReactor.State.usersをbindしてやれば終わりです。
import UIKit
import RxSwift
import ReactorKit
final class UserListViewController: UIViewController, View {
// MARK: - Variables
var disposeBag = DisposeBag()
...
// MARK: - Bind Methods
func bind(reactor: UserListReactor) {
// State
reactor.state.map { $0.users }
.distinctUntilChanged()
.bind { users in
// tableView or collectionViewの更新
}
.disposed(by: disposeBag)
}
}