1

I'm working on a iOS project require pagination (API call will have a page parameter to pull results). The ideal is when user scroll near the bottom of collectionView, a call to API will happen to fetch more results (increase page number) then add new result to existing array of model.

Here is my implementation that work when user search:

This is PhotoListViewReactor

import RxSwift
import RxCocoa
import ReactorKit

class PhotoListViewReactor : Reactor {

  enum Action {
    case searchFlickr(_ keyword: String, _ page: Int)
  }

  enum Mutation {
    case flickrList([Photos])
  }

  struct State{
    var keyword : String?
    var photos : [Photos] = []
    var page: Int = 1
  }

  var initialState: State = State()

  init() { }

  func mutate(action: Action) -> Observable<Mutation> {
    switch action {
    case let .searchFlickr(keyword,page):
      return AppService.request(keyword: keyword,page: page)
              .catchErrorJustReturn([])
              .map{[Photos(photos: $0)]}
              .map {Mutation.flickrList($0)}
    }
  }

  func reduce(state: State, mutation: Mutation) -> State {
    var newState = state
    switch mutation {
        case let .flickrList(photos):
            newState.photos += photos
            newState.page += 1
    }


    return newState
  }

}

The function for get data from API is

static func request(keyword: String, page: Int) -> Observable<[Photo]>

I have added a page: Int to State struct but don't know how to implement page (increase page and call API when user scroll near the bottom)

0

1 Answer 1

2

Here is a solution I wrote with RxSwift. The gist comes with both the code and unit tests. https://gist.github.com/danielt1263/10bc5eb821c752ad45f281c6f4e3034b

It handles the following:

protocol PaginationUISource {
    var reloadLastPage: Observable<Void> { get } /// reload most recently loaded page
    var loadNextPage: Observable<Void> { get } /// load next page
    var bag: DisposeBag { get }
}

protocol PaginationNetworkSource {
    associatedtype Item
    func loadData(page: Int) -> Observable<[Item]>
}

struct PaginationSink<T> {
    let isLoading: Observable<Bool> /// true if network loading is in progress.
    let elements: Observable<[T]> /// elements from all loaded pages
    let error: Observable<Error> /// fires once for each error
}

I wrote this a while ago and I think I could do better now, but it should help you get started.

Sign up to request clarification or add additional context in comments.

3 Comments

thanks. let's me see how i can implement that. but trying to implement reactorKit approach. It's quite clear in the concept and can be apply with more complicate system
I have updated the gist for Swift 4.2, and improved it.
@DanielT. The gist link is not exists. Can you update link?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.