Advanced RxJS Patterns in Angular

Advanced RxJS Patterns in Angular

Advanced RxJS Patterns in Angular

RxJS is a powerful tool for handling reactive programming in Angular applications. Beyond basic observables, RxJS provides advanced patterns that optimize performance, enhance user experience, and simplify complex workflows.

What You Will Learn

  • Implementing Infinite Scrolling with RxJS
  • Optimizing Performance with shareReplay
  • Handling User Authentication Streams

1. Implementing Infinite Scrolling with RxJS

Infinite scrolling is a common UI pattern where more data loads automatically as the user scrolls. Instead of making multiple API requests unnecessarily, we can use RxJS with Intersection Observer for an optimized experience.

๐Ÿ“ฆ Service: Fetch Posts


@Injectable({ providedIn: 'root' })
export class PostService {
  private apiUrl = 'https://jsonplaceholder.typicode.com/posts';

  constructor(private http: HttpClient) {}

  getPosts(page: number, limit: number): Observable<any> {
    return this.http.get(`${this.apiUrl}?_page=${page}&_limit=${limit}`);
  }
}
    

๐Ÿ“„ Component: Infinite Scroll


@Component({
  selector: 'app-infinite-scroll',
  template: `
    <div *ngFor="let post of posts">
      {{ post.title }}
    </div>
    <div #loadMore>Loading...</div>
  `
})
export class InfiniteScrollComponent implements AfterViewInit {
  @ViewChild('loadMore', { static: false }) loadMore!: ElementRef;
  posts: any[] = [];
  currentPage = 1;
  limit = 10;

  constructor(private postService: PostService) {}

  ngAfterViewInit(): void {
    const observer = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) {
        this.loadMorePosts();
      }
    });
    observer.observe(this.loadMore.nativeElement);
  }

  loadMorePosts() {
    this.postService.getPosts(this.currentPage++, this.limit).subscribe(data => {
      this.posts = [...this.posts, ...data];
    });
  }
}
    

✅ Why This Works:

  • Only fetches data when user scrolls to the end.
  • Uses Intersection Observer API to efficiently monitor scroll position.

2. Optimizing Performance with shareReplay

shareReplay caches emitted values to prevent repeated API calls. This enhances performance, especially when the same data is needed by multiple components.

๐Ÿ“ฆ User Service with Caching


@Injectable({ providedIn: 'root' })
export class UserService {
  private userData$: Observable<any>;

  constructor(private http: HttpClient) {
    this.userData$ = this.http.get('https://api.example.com/user').pipe(
      shareReplay(1) // Cache the latest response
    );
  }

  getUser(): Observable<any> {
    return this.userData$;
  }
}
    

๐Ÿ“„ Component Usage


@Component({
  selector: 'app-user',
  template: `
    {{ user$ | async | json }}
  `
})
export class UserComponent implements OnInit {
  user$ = this.userService.getUser();

  constructor(private userService: UserService) {}
  ngOnInit() {}
}
    

✅ Benefits:

  • Prevents duplicate API calls.
  • Improves performance by caching.
  • Ideal for shared data like user profiles.

3. Handling User Authentication Streams

BehaviorSubject is great for managing authentication state across components. It always returns the latest value upon subscription.

๐Ÿ” Auth Service


@Injectable({ providedIn: 'root' })
export class AuthService {
  private authState = new BehaviorSubject<boolean>(false);
  authState$ = this.authState.asObservable();

  login() {
    setTimeout(() => this.authState.next(true), 1000); // Simulate login
  }

  logout() {
    this.authState.next(false);
  }
}
    

๐Ÿ“„ Auth Component


@Component({
  selector: 'app-auth',
  template: `
    <button (click)="login()">Login</button>
    <button (click)="logout()">Logout</button>
  `
})
export class AuthComponent {
  auth$ = this.authService.authState$;

  constructor(private authService: AuthService) {}

  login() { this.authService.login(); }
  logout() { this.authService.logout(); }
}
    

✅ Advantages:

  • Real-time updates to all components.
  • Cleaner state management without manual event emitters.

๐Ÿงพ Summary of Patterns

Pattern Use Case
Infinite Scrolling Lazy-load data as the user scrolls
shareReplay(1) Cache shared data, avoid repeated calls
BehaviorSubject for Auth Global login/logout state management

๐Ÿš€ Bonus Tips

  • Use interfaces for type safety (e.g., Post, User).
  • Include StackBlitz demo links for live example trials.
  • Watch out for memory leaks with shareReplay on hot observables.
  • Refer to official Angular and RxJS docs for best practices.

Comments

Popular posts from this blog

Debouncing & Throttling in RxJS: Optimizing API Calls and User Interactions

Promises in Angular

Comprehensive Guide to C# and .NET Core OOP Concepts and Language Features