Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds
Arrow up icon
GO TO TOP
RxJS Cookbook for Reactive Programming

You're reading from   RxJS Cookbook for Reactive Programming Discover 40+ real-world solutions for building async, event-driven web apps

Arrow left icon
Product type Paperback
Published in Mar 2025
Publisher Packt
ISBN-13 9781788624053
Length 310 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Nikola Mitrovic Nikola Mitrovic
Author Profile Icon Nikola Mitrovic
Nikola Mitrovic
Arrow right icon
View More author details
Toc

Table of Contents (13) Chapters Close

Preface 1. Handling Errors and Side Effects in RxJS 2. Building User Interfaces with RxJS FREE CHAPTER 3. Understanding Reactive Animation Systems with RxJS 4. Testing RxJS Applications 5. Performance Optimizations with RxJS 6. Building Reactive State Management Systems with RxJS 7. Building Progressive Web Apps with RxJS 8. Building Offline-First Applications with RxJS 9. Going Real-Time with RxJS 10. Building Reactive NestJS Microservices with RxJS 11. Index
12. Other Books You May Enjoy

Fetching data with the Infinite Scroll Timeline component

Imagine going through your favorite cooking web application and getting the latest updates on delicious new recipes. To show this latest news, one of the common UX patterns is to show this recipe news in a timeline component (such as Facebook’s news feed). While you scroll, if there are new recipes, you’ll be updated that there are fresh new recipes so that you can scroll back to the top and start over.

How to do it…

In this recipe, we’re going to build a timeline component that shows the list of your favorite latest cooking recipes. Since there are a lot of delicious recipes out there, this would be a huge list to fetch initially. To increase the performance of the application and to improve the general UX, we can implement an infinite scroll list so that once the user scrolls to the end of a list of 5 initial recipes, we can get a set of 5 new recipes. After some time, we can send a new request to check whether there are new recipes and refresh our timeline of recipe news.

Step 1 – Detecting the end of a list

In our RecipesList component, we’ll create a stream of scroll events. On each emission, we’ll check whether we’re near the end of the list in the UI based on a certain threshold:

private isNearBottom(): boolean {
    const threshold = 100; // Pixels from bottom
    const position = window.innerHeight + window.scrollY;
    const height = document.documentElement.scrollHeight;
    return position > height - threshold;
}
const isNearBottom$ = fromEvent(window, 'scroll').pipe(
    startWith(null),
    auditTime(10), // Prevent excessive event triggering
    observeOn(animationFrameScheduler),
    map(() => this.isNearBottom()),
    distinctUntilChanged(), // Emit only when near-bottom 
                             //state changes
)

As you can imagine, with the scroll event emissions, there’s the potential for performance bottlenecks. We can limit the number of scroll events that are processed by the stream using the auditTime operator. This is especially useful since we want to ensure that we are always processing the latest scroll event, and auditTime will always emit the most recent value within the specified time frame. Also, with observeOn(animationFrameScheduler), we can schedule tasks to be executed just before the browser’s next repaint. This can be beneficial for animations or any updates that cause a repaint as it can help to prevent jank and make the application feel smoother.

auditTime versus throttleTime

You might be wondering why we used auditTime in our scroll stream and not throttleTime. The key difference between these two operators is that auditTime emits the last value in a time window, whereas throttleTime emits the first value in a time window. Common use cases for throttleTime might include rate-limiting API calls, handling button clicks to prevent accidental double clicks, and controlling the frequency of animations.

Once we know we’re getting near the end of a list, we can trigger a loading state and the next request with a new set of data.

Step 2 – Controlling the next page and loading the state of the list

At the top of our RecipesList component, we’ll define the necessary states to control the whole flow and know when we require the next page, when to show the loader, and when we’ve reached the end of the list:

private page = 0;
public loading$ = new BehaviorSubject<boolean>(false);
public noMoreData$ = new Subject<void>();
private destroy$ = new Subject<void>();

Now, we can continue our isNearBottom$ stream, react to the next page, and specify when to show the loader:

isNearBottom$.pipe(  
    filter((isNearBottom) =>
        isNearBottom && !this.loading$.value),
    tap(() => this.loading$.next(true)),
    switchMap(() =>
        this.recipesService.getRecipes(++this.page)
        .pipe(
            tap((recipes) => {
                if (recipes.length === 0)
                this.noMoreData$.next();
            }),
            finalize(() => this.loading$.next(false))
        )
    ),
    takeUntil(merge(this.destroy$, this.noMoreData$))
    )
    .subscribe((recipes) => (
        this.recipes = [...this.recipes, ...recipes])
    );
}

Here’s a breakdown of what we’ve done:

  1. First, we check whether we’re near the bottom of the page or whether there’s already an ongoing request.
  2. We start a new request by showing a loading spinner.
  3. We send a new request with the next page as a parameter.
  4. When we get a successful response, we can check whether there’s no more data or we can continue scrolling down the timeline.
  5. Once the stream has finished, we remove the loading spinner:
Figure 2.12: Reactive infinite scroll

Figure 2.12: Reactive infinite scroll

Step 3 – Checking for new recipes

In our recipes.service.ts file, we’ve implemented a method that will check whether there are new recipes periodically and whether we should scroll to the top of the timeline and refresh it with new data:

checkNumberOfNewRecipes(): Observable<number> {
    return interval(10000).pipe(
        switchMap(() =>
            this.httpClient.get<number>(
                '/api/new-recipes'))
    );
}

Once we receive several new recipes, we can subscribe to that information inside NewRecipesComponent and display it in the UI:

Figure 2.13: Reactive timeline updates

Figure 2.13: Reactive timeline updates

Now, once we click the 2 new recipes button, we can scroll to the top of the timeline and get the newest data.

See also

You have been reading a chapter from
RxJS Cookbook for Reactive Programming
Published in: Mar 2025
Publisher: Packt
ISBN-13: 9781788624053
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime