4

In MVI with the Mosby library, what is the best way to access the state outside of the reducer function in the stream? For example, when you need to load the next page for your recycler, you need to know which page was loaded last. (In the sample app the last page is saved in the loader but that defeats the whole purpose of having a single state POJO)

4

1 回答 1

2

There are multiple ways to do that and depending on how your pagination url is constructed, you may not need a reference to the privous state at all.

For example let's say that you can access next page via a number. So the http request looks like this: http://www.foo.com/feed?page=1 next page is http://www.foo.com/feed?page=2 and so on.

Then you can basically do something like this:

Observable<Integer> nextPageIntent = intent(YourView::loadNextPageIntent)
                                    .scan(1, (previousPage, ignored) -> previousPage + 1);

Observable<State> state = nextPageIntent.switchMap(page -> backend.loadPage(page).map(...) )
                                        .startWith(...)
                                        .onErrorReturn(...);

So the trick is to add some "counter". Whenever YourView::loadNextPageIntent is triggered, we increment the page by one in .scan(1, (previousPage, ignored) -> previousPage + 1). So this basically emits 1, 2, 3, 4, 5, ... and then loads the corresponding page from your backend.

However, if you really need a reference to your previous state to determine the next page url you can model your state reducer slightly differently by using a BehaviorSubject instead of .scan() operator like this (cretits Paco Estevez):

BehaviorSubject<State> state = BehaviorSubject.createDefault(initialState);
state.switchMap( oldState ->
        intent(YourView::loadNextPageIntent)
               .switchMap( ignored -> backend.loadPage(oldState.nextPageUrl) // You can access oldState now
                            .map(...))
                            .startWith(...)
                            .onErrorReturn(...)
).subscribe(state);


subscribeViewState(state, YourView::render)

The trick here is that you use a Subject which subscribes to itself. Basically it is the very similar to what .scan() operator does to implement a reducer but now you have the reference to the old state.

于 2017-08-02T00:38:02.653 回答