在组件的构造函数中分派动作时,不会调用ngrx效果

时间:2020-01-09 19:33:34

标签: angular ngrx ngrx-effects

这是我的应用程序模块:

@NgModule({
  declarations: [
    SampleA
  ],
  imports: [
    BrowserModule,
    EffectsModule.forRoot([APIEffects]),
    HttpClientModule,
    StoreModule.forRoot(reducers),
    StoreDevtoolsModule.instrument({
      maxAge: 25, // Retains last 25 states
      logOnly: environment.production, // Restrict extension to log-only mode
    }),
    KeyboardShortcutsModule.forRoot()
  ],
  providers: [
    APIService,
    {
      provide: HTTP_INTERCEPTORS,
      useClass: HttpMockRequestInterceptor,
      multi: true
    }
  ],
  bootstrap: [],
  entryComponents: [
    SampleComponent
  ]
})
export class AppModule{...}

这里是APIEffect

@Injectable()
export class APIEffects {
  fetchData$ = createEffect(() => this.actions$.pipe(
    ofType(Actions.apiFetchData),
    mergeMap((action) => this.apiService.fetchData(...action)
          .pipe(
            map(data => Actions.apiSuccess({ data })),
            catchError(() => of(Actions.apiCallFailed()))
          )
    )
  ));
}

现在,如果我在apiFetchData构造函数中分配SampleComponent动作,则不会调用该效果:

export class SampleComponent {
    constructor(private store: Store<{ state: State }>) {
        store.dispatch(Actions.apiFetchData(...))
    }
}

如果我稍后在组件的生命周期中调度相同的操作,则一切正常,效果会发生。

Redux DevTools中,我可以看到动作分配发生在effects init之前。这是命令:

@ngrx/store/init
[API] fetch data // this is the fetch data action
@ngrx/effects/init

所以我的问题是如何在构造组件之前强制效果初始​​化。

更新

我还没有解决上面提到的问题,但是现在,我决定使用ROOT_EFFECTS_INIT(感谢@mitschmidt提及),并在effects之后准备初始化我的应用程序的状态。这是使用ROOT_EFFECTS_INIT的效果:

  init$ = createEffect(() =>
    this.actions$.pipe(
      ofType(ROOT_EFFECTS_INIT),
      map(action => CoverageUIActions.apiFetchData({...}))
    )
  );

1 个答案:

答案 0 :(得分:1)

为了实现这一点,您可能希望查看NGRX生命周期事件,例如ROOT_EFFECTS_INIT,如下所述:https://ngrx.io/guide/effects/lifecycle

使用APP_INITIALIZER注入令牌(良好的教程here)和必要的语法糖,您可以构建一个应用初始化服务,该服务将延迟您的应用自举,直到注册了NGRX根效果为止(没有任何组件在这种情况下进行初始化,那么您在构造函数内部的逻辑应该可以正常工作)。 在最近的项目中,我走了一条类似的路:

export class AppInitializer {
  constructor(private readonly actions$: Actions) {}

  initialize() {
    return this.actions$.pipe(ofType(ROOT_EFFECTS_INIT));
  }
}
  return (): Promise<any> => {
    return appInitializer.initialize().toPromise();
  };
}

...,最后将提供程序添加到您的模块中:

import { appInitializerFactory } from './app-initializer.factory';

export const APP_INITIALIZER_PROVIDER: Provider = {
  provide: APP_INITIALIZER,
  useFactory: appInitializerFactory,
  deps: [AppInitializer],
  multi: true,
};
// your module...
{
...
  providers: [APP_INITIALIZER_PROVIDER]
...
}