Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

can ngrx store.dispatch be throttled / debounced or can ngrx actions be throttled / debounced?

Tags:

angular

ngrx

I am using ngrx 6 with angular 6

In my ngrx store devtools I see that one of my actions is firing more often than I want. It's not breaking the app, its just cluttering the devtools output.

I am dispatching the action with:

this.store.dispatch(new RecentSearchesRequestedAction())

How can I best debounce / throttle this so that it does not dispatch more than once per second for example? Does ngrx have a built in solution? I know I could spend time working out why the action is firing so often but I don't really have time for that. What's best practice to achieve this? Thanks

like image 920
danday74 Avatar asked Nov 16 '25 19:11

danday74


2 Answers

The best solution would be to debounce whatever is calling this.store.dispatch, which would be outside ngrx.

You can throttle the output side of ngrx, for example:

this.store.select((x) => x.property)
.pipe(
    debounceTime(1000)
).subscribe((v) => console.log(v));

... would log the value of x.property at most once per second. But to stop the inputs, you need to throttle before the calls are made to dispatch.

like image 126
Mark Hughes Avatar answered Nov 18 '25 08:11

Mark Hughes


This is a complementary answer to the accepted one and dives into more details about where to actually place the debounce.

When working with FormControls it is simple to debounce because of valueChanges (example):

this.searchField.valueChanges
  .debounceTime(400)
    .switchMap(term => this.searchService.search(term))
    .subscribe((result) => {
        this.result = result.items
    });

This relies on switchMap function which cancels existing calls and keeps the latest one.

When working with custom controls, cancellation typically requires custom code (example for a Kendo control which does not emit changes, but relies on events):

After value change directive that applies the debouncing

import { Directive, Input, HostListener, OnDestroy, Output, EventEmitter } from '@angular/core';
import { Subject, Subscription } from 'rxjs';
import { debounceTime } from 'rxjs/operators';

@Directive({
  selector: '[afterValueChanged]'
})
export class AfterValueChangedDirective implements OnDestroy {
  @Output()
  public afterValueChanged: EventEmitter<any> = new EventEmitter<any>();

  @Input()
  public valueChangeDelay = 300;

  private stream: Subject<any> = new Subject<any>();
  private subscription: Subscription;

  constructor() {
    this.subscription = this.stream
      .pipe(debounceTime(this.valueChangeDelay))
      .subscribe((value: any) => this.afterValueChanged.next(value));
  }

  ngOnDestroy(): void {
    this.subscription.unsubscribe();
  }

  @HostListener('valueChange', [ '$event' ])
  public onValueChange(value: any): void {
    this.stream.next(value);
  }
}

Usage

<kendo-numerictextbox
  (afterValueChanged)="onAfterValueChange($event)"
  (valueChange)="onValueChange($event)">
</kendo-numerictextbox>

public onAfterValueChange(value: number): void {
   this.value = value;
}
like image 20
Alexei - check Codidact Avatar answered Nov 18 '25 09:11

Alexei - check Codidact



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!