使用 NgRx Router Store 在同一页面上导航时的调度操作

Dispatch action when navigating on the same page with NgRx Router Store

我目前正在使用 NgRx 和 Router Store 构建应用程序。 一个组件中有一个下拉菜单,它会更改 url 中的参数并在同一组件上导航。 由于在同一组件上导航不会调用 NgOnInit,因此不会调用相应的效果(调用 API)。 在我看来,如果组件更改了参数,则应始终调用效果。

loadTransactions$ = createEffect(() => this.actions$.pipe(
  ofType(
    NavigationActions.ActionType.NavigateToTransactionsSuccess,
    TransactionsPageActions.ActionType.LoadPage
  ),
  [...]
));

我的一个想法是创建一个自定义操作,它只监听带有下拉列表的组件上的导航,但我不知道该怎么做。

我目前的解决方案如下:

this.store.select(RouterSelectors.selectUrl).subscribe(() =>
  this.store.dispatch(TransactionsPageActions.loadPage())
);

但是感觉以后可能会出现一些bug。 有什么方法可以干净地实现这一点?

既然你想通过路由控制数据的加载,那么通过 routeGuards,特别是 CanActivate Guard

下面是一个可能的方法的简单片段,

routing.module.ts

const routes: Routes = [
  {
    path: '',
component: ShellPageComponent,
canActivate: [],
children: [

  {
    path: '',
    component: MainParentComponent,
    children: [
      {
        path: ':transactionId',
        
        canActivate: [TransactionGuard],
            component:TransactionComponent
            
          },

 
          { path: '**', redirectTo: 'MainParentComponent' }
        ]
      },
     
    ]
  }
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class  RoutingModule {}

交易-page.guard.ts

@Injectable({
  providedIn: 'root'
})
export class TransactionGuard implements CanActivate {
  constructor( private store: Store<any>  ) {}

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean | UrlTree> {
 

    const transcationId = route.paramMap.get('transactionId')
    //assuming  TransactionIsLoadedSelector is a selector to verify if transaction has been loaded and returns a Boolean

    return this.store.select(TransactionIsLoadedSelector$,{id:transcationId}).pipe(
      tap((TransactionIsLoaded)=>{
        if(!TransactionIsLoaded){
          this.store.dispatch(TransactionsPageActions.loadPage())
        }
      }),
      filter((TransactionIsLoaded)=> TransactionIsLoaded)

        
    )
  }

}

我仔细阅读了文档,effects guide 告诉您以下内容:

Note: Event streams are not limited to dispatched actions, but can be any observable that produces new actions, such as observables from the Angular Router, observables created from browser events, and other observable streams.

所以我实现了一个自定义路由器操作并将其发送到一个效果中,当路由器存储中的 accountId 更改时调用它。

accountIdChanged$ = createEffect(() => this.store.select(
   RouterSelectors.selectRouteParam('accountId')
).pipe(
   map((accountId) => RouterActions.accountIdChanged({accountId}))
));

现在我可以随时随地收听该动作,例如在我的交易效果中。

loadTransactions$ = createEffect(() => this.actions$.pipe(
   ofType(RouterActions.ActionType.AccountIdChanged),
   // [...]
));