Search code examples
angularreduxngrxngrx-storengrx-effects

How prevent loading data second time in NgRx?


I have a DOM block:

<div (click)="toggle(block)">
   <div *ngIf="block.opened">
     <div *ngFor="let item of block.items"></div>
   </div>
</div>

By click I dispatch action to load data from server and display this data in block:

  toggle(block: RegistryGroup) {
    this.store.dispatch(RegistryActions.ToggleRegistryBlockAction(block));
    this.store.dispatch(RegistryActions.LoadRegistryLayersAction(this.block));
  }

First event ToggleRegistryBlockAction changes property of block to true/false. The second LoadRegistryLayersAction makes request to the server by block.id and returns data to the same state of block to the property block.items = Server Response;

In effect side where I listen action LoadRegistryLayersAction:

loadRegistriesLayers$: Observable<Action> = createEffect(() =>
    this.actions$.pipe(
      ofType(RegistryActions.LoadRegistryLayersAction),
      filter(
        (registryGroup) =>
          registryGroup.items && !registryGroup.items.length
      ),
      switchMap((registryGroup: RegistryGroup) =>
        from(this.registry.getRegistryLayers(registryGroup.Id)).pipe(
          map((layers: { [key: string]: RegistryLayerItemGeneric[] }) => {
            return RegistryActions.SuccessLoadRegistryLayersAction({
              payload: {
                layers: this.registry.createLayersMapWithObjects(layers),
                registryGroupId: registryGroup.Id,
              },
            });
          }),
          catchError((error: Error) => {
            return of(RegistryActions.ErrorRegistryLayersAction(error));
          })
        )
      )
    )
  );

I filter action and check if data already present. For that I check if block has registryGroup.items && !registryGroup.items.length.

Problem is that sometimes after execution this effects server can return empty []. So next time, when user requests it, it sends request repeatly.

How to fix it and dont touch server if data was loaded?


Solution

  • There are multiple solutions:

    • keep a status property which can be loading, loaded, empty,...
    • keep a list of id's that are fetched in the state, and check this list before sending the request
    • don't check on registryGroup.items.length, and initialize the array as null