You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular5中如何监听Ngrx动作/效果完成并通知组件?

Hey there! Let's break down your two questions one by one, since they're both about tracking NgRx action/effect completion in Angular 5.


问题1:Angular5环境下,如何在Ngrx动作/效果执行完成时收到通知?

In NgRx (matching Angular 5, you're likely using NgRx 4 or 5), there are a few practical ways to track when an action or effect finishes—pick the one that fits your use case:

  • Listen to the global action stream
    You can directly subscribe to store.actions$ and filter for the "completion" actions your effects dispatch (usually a success or failure action after async work finishes). Here's an example:

    import { Store } from '@ngrx/store';
    import { filter, takeUntil } from 'rxjs/operators';
    import { Subject } from 'rxjs';
    
    private destroy$ = new Subject<void>();
    
    constructor(private store: Store) {}
    
    ngOnInit() {
      this.store.actions$.pipe(
        filter(action => 
          action.type === '[Upload] Presign Success' || 
          action.type === '[Upload] Presign Failure'
        ),
        takeUntil(this.destroy$) // Clean up subscription when component destroys
      ).subscribe(action => {
        if (action.type === '[Upload] Presign Success') {
          console.log('Upload presign action completed successfully!');
          // Add your notification logic here—update UI, show a toast, etc.
        } else {
          console.error('Upload presign failed:', action.payload);
        }
      });
    }
    
    ngOnDestroy() {
      this.destroy$.next();
      this.destroy$.complete();
    }
    
  • Track via effect output actions
    First, make sure your effect handles the trigger action, runs async logic, and dispatches a completion action. For example:

    import { Injectable } from '@angular/core';
    import { Actions, Effect } from '@ngrx/effects';
    import { of } from 'rxjs';
    import { map, catchError, switchMap } from 'rxjs/operators';
    
    @Injectable()
    export class UploadEffects {
      @Effect()
      uploadPresign$ = this.actions$.pipe(
        ofType(UploadActions.UploadPresignAction),
        switchMap(action => {
          // Your async logic here—e.g., call an API for presign token
          return this.uploadApi.getPresignToken(action.jwt, action.file)
            .pipe(
              map(res => new UploadActions.UploadPresignSuccessAction(res)),
              catchError(err => of(new UploadActions.UploadPresignFailureAction(err)))
            );
        })
      );
    
      constructor(private actions$: Actions, private uploadApi: UploadApiService) {}
    }
    

    When the async work finishes, the effect will automatically dispatch a success/failure action—just listen for those in your component.


问题2:如何让组件收到UploadPresignAction分发完成的通知?

First, let's fix a subtle bug in your code: you're dispatching the action outside the userDetails$ subscription, but subscriptions are async. That means this.userDetails might not be set yet, leading to undefined for this.userDetails.jwt. Move the dispatch inside the subscription:

onUpload($event: SubmissionFileUpload) {
  this.homeService.getUserDetails().subscribe(res => {
    this.userDetails = res;
    // Dispatch only after we have the jwt
    this.store.dispatch(new UploadActions.UploadPresignAction(this.userDetails.jwt, $event));
  });
}

Now, here are two solid ways to notify your component when the action completes:

方案1:Return an Observable from onUpload for the component to subscribe to

Modify your uploadService method to return an Observable that emits when the action finishes:

import { Store } from '@ngrx/store';
import { switchMap, filter, take } from 'rxjs/operators';

onUpload($event: SubmissionFileUpload) {
  return this.homeService.getUserDetails().pipe(
    switchMap(res => {
      this.userDetails = res;
      this.store.dispatch(new UploadActions.UploadPresignAction(res.jwt, $event));
      // Listen for success/failure, take(1) ensures we only get one result
      return this.store.actions$.pipe(
        filter(action => 
          action.type === '[Upload] Presign Success' || 
          action.type === '[Upload] Presign Failure'
        ),
        take(1)
      );
    })
  );
}

Then in your component:

this.uploadService.onUpload({ some: data }).subscribe(action => {
  if (action.type === '[Upload] Presign Success') {
    // Action completed—run your logic
    alert('Upload presign finished successfully!');
  } else {
    console.error('Upload failed:', action.payload);
  }
});

方案2:Listen to store state changes (more aligned with NgRx principles)

If your reducer updates state when the action completes (e.g., adds an uploadStatus field), you can listen to that state in your component.

First, update your reducer to track status:

export interface UploadState {
  uploadStatus: 'idle' | 'loading' | 'completed' | 'failed';
  // Other state fields...
}

const initialState: UploadState = {
  uploadStatus: 'idle'
};

export function uploadReducer(state = initialState, action: UploadActions.UploadActions) {
  switch (action.type) {
    case UploadActions.UPLOAD_PRESIGN:
      return { ...state, uploadStatus: 'loading' };
    case UploadActions.UPLOAD_PRESIGN_SUCCESS:
      return { ...state, uploadStatus: 'completed' };
    case UploadActions.UPLOAD_PRESIGN_FAILURE:
      return { ...state, uploadStatus: 'failed' };
    case UploadActions.RESET_UPLOAD_STATUS:
      return { ...state, uploadStatus: 'idle' };
    default:
      return state;
  }
}

Create a selector for the status:

import { createFeatureSelector, createSelector } from '@ngrx/store';
import { UploadState } from './upload.reducer';

export const selectUploadState = createFeatureSelector<UploadState>('upload');
export const selectUploadStatus = createSelector(
  selectUploadState,
  state => state.uploadStatus
);

Then listen to it in your component:

import { Store } from '@ngrx/store';
import { selectUploadStatus } from './store/upload.selectors';
import { takeUntil } from 'rxjs/operators';

private destroy$ = new Subject<void>();

constructor(private store: Store) {}

ngOnInit() {
  this.store.select(selectUploadStatus).pipe(
    takeUntil(this.destroy$)
  ).subscribe(status => {
    if (status === 'completed') {
      console.log('Upload presign completed!');
      // Reset status to avoid duplicate notifications on next action
      this.store.dispatch(new UploadActions.ResetUploadStatusAction());
    } else if (status === 'failed') {
      console.error('Upload presign failed');
    }
  });
}

ngOnDestroy() {
  this.destroy$.next();
  this.destroy$.complete();
}

This approach uses state changes to drive UI updates, which fits NgRx's unidirectional data flow pattern.


内容的提问来源于stack exchange,提问作者Shamoon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:54:36