1
votes

What is the best way to implement a paging solution in RxJs?

If want to have an observable that emits new data based on an event (could be a click, or a JavaScript function call). For instance if I have an Observable retrieving data from a Web API, and I don't want it to just keep on hammering away HTTP requests, I only want that to happen on an event triggered by the subscriber. Scenarios could be infinite scrolls (event triggered by scrolling), classic paging (event triggered by user clicking on next page) etc.

1
pageChange$.pipe(switchMap(page => getItems(page))) would be a start, with pageChange$ being a Subject<number> - Ingo Bürk
Thanks all, added a working example based on newer versions of RxJs - Wictor Wilen MCA MCM MVP
I've always just used a combination of take(itemsInPage) and skip(previousRows). Or you could just implement paging on your api side and forget about it in your UI. - Mr. Young

1 Answers

1
votes

This is the solution I came up with based on the comments and using RxJs 6.3.3

export default class Test extends React.Component<any, any> {

  private subscription: Subscription;

  public componentDidMount() {
    const client = new MyClient();
    let source = client.get('/data');

    const buttonNotifier = defer(() => {
      console.log("waiting");
      return fromEventPattern(
        (handler) => { this.next = handler; }
      ).pipe(tap(() =>
        console.log("sending more data")
      ));
    });

    const pagedData: Observable<{Value:any, NextLink:string}> = source.pipe(
      expand(({ NextLink }) => NextLink ?
      buttonNotifier.pipe(take(1), concatMap(() => client.get(NextLink))) :
      empty()));

    this.subscription = pagedData.subscribe(
      result => {
          this.setState({
          Value: result.Value,
        });
      },
      error => {
        this.setState({
          Error: `ERROR: ${error}`
        });
      },
      () => {
        this.setState({
          Done: `DONE`
        });
      }
    );
  }

  public componentWillUnmount() {
    if (this.subscription) {
      this.subscription.unsubscribe();
    }
  }

  private next: Function;

  public render(): React.ReactElement<any> {
    return (<button onClick={()=> {this.next();}}>Next</button>);
  }
}