JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.7/rx.all.js"></script>
<ol id="log">
</ol>
CSS
#log li.first {
color: green;
}
#log li.second {
color: blue;
}
#log li.service {
color: grey;
}
JavaScript
const logDiv = $("#log");
function log(message, cls) {
logDiv.append($("<li>").text(message).addClass(cls));
}
/* interface IRequest {
url: string;
page: number:
refresh?: boolean
}
interface IEndpoint {
get(request: IRequest): [];
} */
// Class that represents a cursor into paginated data
function PagedData(endpoint, url) {
this._endpoint = endpoint;
this._url = url;
// Our request queue is an observable of structurs of type IRequest
// We use a reply subject so that the last URL requested is in the stream when the first subscriber subscribes.
this._requestQueue = new Rx.ReplaySubject(1);
// This is our data observable, subscribe to it to
// A) receive the last page that this cursor has produced
// B) receive all future pages
this.items$ = this._requestQueue
// Don't re-query unless the "refresh" boolean is true
.distinctUntilChanged(req => req, (left, right) => right.refresh ? false : left.page == right.page)
// Make the request...
.flatMapLatest(request => Rx.Observable.of(request).zip(this._endpoint.get(request)))
// Wrap data returned with an envelope with data such as which page was requested
.map(data => {
const request = data[0];
const response = data[1];
return {
page: request.page,
url: request.url,
items: response
};
})
// Replay last page worth of data on each subscription
.shareReplay(1);
// Queue up the first page to be retrieved on first subscription
this.getPage(1);
}
PagedData.prototype.getPage = function(page, refresh) {
refresh = refresh || false;
// Fire off the workflow
this._requestQueue.onNext({
url: this._url,
refresh: refresh,
page: page
});
}
PagedData.prototype.dispose = function() {
// Question: this should unsubscribe ALL of the subscriptions to this.items$, right?
this._requestQueue.completed();
}
// -----------------
// EXAMPLE USAGE
var dummyEndpoint = {
get(request) {
log(`GET: ${request.url} at page ${request.page}`, "service");
return...