I have a favorite Button, the button isSelected
changed by the network data and tap the button. When the isSelected by tap the button, it need to request the favorite or unfavorite API, but when it changed by the network data, it is not need to request api.
It is my code, when the isSelected changed it always request the api.
// in viewmodel
isFavorite = selectedVideo
.map { $0.isFavorite ?? false }
.flatMapLatest({ favorite in
onTapFavorite.scan(favorite) { acc, _ in !acc }.startWith(favorite)
})
.distinctUntilChanged()
// when subscribe
Observable.combineLatest(viewModel.isFavorite, viewModel.selectedVideo)
.flatMapLatest({ (isFavorite, video) in
if isFavorite {
return APIService.favoriteVideo(videoId: video.videoId)
} else {
return APIService.unfavoriteVideo(videoId: video.videoId)
}
})
.subscribe(onNext: { _ in
}).disposed(by: disposeBag)
You have two features, so you should have two Observable chains...
The server update chain looks like this:
func updateServer(selectedVideo: Observable<Video>, onTapFavorite: Observable<Void>) -> Observable<(videoId: Video.ID, isFavorite: Bool)> {
selectedVideo
.flatMapLatest { video in
onTapFavorite
.scan(video.isFavorite ?? false) { isFavorite, _ in !isFavorite }
.map { (videoId: video.id, isFavorite: $0) }
}
}
And is bound like this:
updateServer(selectedVideo: selectedVideo, onTapFavorite: favoriteButton.rx.tap.asObservable())
.flatMapLatest {
$0.isFavorite ? APIService.favoriteVideo(videoId: $0.videoId) : APIService.unfavoriteVideo(videoId: $0.videoId)
}
.subscribe(onError: { error in
// handle error
})
.disposed(by: disposeBag)
For the isSelected property, use a different Observable chain:
func isSelected(selectedVideo: Observable<Video>, onTapFavorite: Observable<Void>) -> Observable<Bool> {
selectedVideo
.map { $0.isFavorite ?? false }
.flatMapLatest { isFavorite in
onTapFavorite
.scan(isFavorite) { isFavorite, _ in !isFavorite }
.startWith(isFavorite)
}
}
which is bound like this:
isSelected(selectedVideo: selectedVideo, onTapFavorite: favoriteButton.rx.tap.asObservable())
.bind(to: favoriteButton.rx.isSelected)
.disposed(by: disposeBag)