【问题标题】:Angular ngrx 8 selector doesn't return any valueAngular ngrx 8 选择器不返回任何值
【发布时间】:2019-12-03 00:08:48
【问题描述】:

我不是 Angular 的新手,但我是 ngrx 的新手。 我正在尝试从我的服务器获取一些值并将它们简单地打印到屏幕上,我可以看到这些值正在从服务器返回,之后效果捕获了动作并完成了它的工作:

但是我的简单组件没有显示任何内容:

ProfileComponent.ts:

export class ProfileComponent implements OnInit {
  network$= this.store.select(a=>a.NetworkInfo)
  profiles$: Observable<Profile[]> = this.store.select(state => state.Profiles);
  constructor(private store:Store<NetAlertState>) { }

  ngOnInit() {
    this.store.dispatch({ type: '[Profile Component] getAllProfiles' });
    this.store.dispatch({ type: '[Profile Component] getNetworkInfo' });    
  }

}

profile.component.html:

    <div *ngFor="let profile of profiles$ | async">
    {{ profile.name }}
    </div>

net-alert.actions.ts:

export const getAllProfiles = createAction('[Profile Component] getAllProfiles');
export const getNetworkInfo = createAction('[Profile Component] getNetworkInfo');
export const loadProfilesSuccess = createAction('[Profile Component] loadProfilesSuccess',props<{items:Profile[]}>());
export const loadNetworkInfoSuccess = createAction('[Profile Component] loadNetworkInfoSuccess', props<NetworkInfo>());
export const loadProfilesFailure = createAction('[Profile Component] loadProfilesFailure',props<String>());
export const loadNetworkInfoFailure = createAction('[Profile Component] loadNetworkInfoFailure',props<String>());

net-alert.reducer.ts

    export const initialState: NetAlertState = {
    Profiles:null,
    NetworkInfo:null,
    isLoading: false,
    error: null
}

export const NetAlertReducer = createReducer(
    initialState,
    on(NetAlertActions.getAllProfiles, state => ({ ...state,isLoading:true ,error:null})),
    on(NetAlertActions.loadProfilesSuccess, (state,profiles) => ({ Profiles:profiles,...state ,isLoading:false ,error:null})),
    on(NetAlertActions.loadProfilesFailure, (state,err) => ({ ...state,isLoading:false ,error:err})),
    on(NetAlertActions.getNetworkInfo, state => ({ ...state ,isLoading:true ,error:null})),
    on(NetAlertActions.loadNetworkInfoSuccess, (state,res) => ({ ...state,NetworkInfo:res,isLoading:false ,error:null})),
    on(NetAlertActions.loadNetworkInfoFailure, (state,err) => ({ ...state,isLoading:false ,error:err})),
  );



export function reducer(state: NetAlertState | undefined, action: Action) {
    return NetAlertReducer(state, action);
  }

net-alert.effects.ts:

@Injectable()
export class NetAlertEffects {

    loadProfiles$ = createEffect(() =>
     this.actions$.pipe(
        ofType('[Profile Component] getAllProfiles'),
        mergeMap(() => this.dataService.getAllProfiles()
          .pipe(
            map(res => ({ type: '[Profile Component] loadProfilesSuccess', payload: res })),
            catchError(() => of({ type: '[Profile Component] loadProfilesFailure' }))
          )
        )
      )
  );

  constructor(
    private actions$: Actions,
    private dataService: DataService
  ) {}
}

net-alert.state.ts:

  export interface NetAlertState {
     isLoading: boolean;
     error: any;
     NetworkInfo: NetworkInfo;
     Profiles: Profile[];
 }

 export interface Profile {
  Mac: string;
  NickName: string;
  CreateDate: Date;
  Sites?: any;
}

root-state.ts:

export interface AppStates {
  netAlert: NetAlertState;
}

export const netAlertReducers: ActionReducerMap<AppStates> = {
    netAlert: netAlertRerucers.reducer
 }; 

app.module.ts:

  @NgModule({
  declarations: [
    AppComponent,
    ProfileContainerComponent,
    ProfileComponent
  ],
  imports: [
    HttpClientModule,
    BrowserModule,
    AppRoutingModule,
    StoreModule.forRoot(netAlertReducers),
    EffectsModule.forRoot([NetAlertEffects]),
    StoreDevtoolsModule.instrument({
      maxAge: 25, // Retains last 25 states
      logOnly: environment.production, // Restrict extension to log-only mode
    }),
    RootStoreModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

谁能告诉我我的错误在哪里?

非常感谢!

【问题讨论】:

  • 当您选择“State”而不是“Action”时,Redux DevTools 中是否显示 Profiles: [] 或类似内容? Toggle 按钮位于 Redux DevTools 的右上角。此外,我没有看到用于选择“netAlert”状态的选择器,您可以在此基础上构建其他选择器

标签: angular typescript ecmascript-6 redux ngrx


【解决方案1】:

如果您没有减速器来从 loadProfilesSuccess 操作更新您的状态,它将无法工作。比如:

const myReducer = createReducer(
  initialState, // type NetAlertState
  on(from.loadProfilesSuccess, (state, action) => {
     // return new state from action payload
  }),
)

export function reducer(state: NetAlertState, action: Action) {
    return myReducer(state, action);
}

您有操作,但您也从未使用过它们。你应该在任何地方使用它们:

ngOnInit() {
    this.store.dispatch(getAllProfiles());
    this.store.dispatch(getNetworkInfo());
}
loadProfiles$ = createEffect(() =>
     this.actions$.pipe(
        ofType(getAllProfiles),
        mergeMap(() => this.dataService.getAllProfiles()
          .pipe(
            map(res => loadProfilesSuccess(res)),
            catchError(() => of(loadProfilesFailure())
          )
        )
      )
    );

【讨论】:

  • 其实我有reducers,只是没注意到这里没有发布主题,我编辑了我的文档。
  • 你的reducer代码错误。第二个参数是action,所以你需要为你的状态使用action.payload。我很惊讶你没有编译错误。此外,您的loadProfilesSuccess 操作中不得包含Observable。您应该在效果中执行此操作,而不是手动创建 {type: '...'}
  • 首先非常感谢您的帮助。我可以举个小例子或更多细节吗?我可以看到你要去哪里,但我仍然错过了一些东西
  • 这是我几个月前开始学习ngrx时写的代码:github.com/vannhi/angular-ngrx-leaflet-example/blob/master/src/…
【解决方案2】:

我没有看到用于选择“netAlert”状态的选择器,您可以在此基础上构建其他选择器,如下所示:

selectors.ts

import * as fromNetAlertState from "./state";

export const netAlertState = (state: State) => state.netAlert;

export const selectProfiles = createSelector(
  netAlertState,
  (state: fromNetAlertState.State) => state.Profiles
);

component.ts

profiles$: Observable<Profile[]> 

ngOnInit() {
    this.profiles$ = this.store.pipe(select(selectProfiles))
}

【讨论】:

    【解决方案3】:

    您应该像这样将您的配置文件 $ 放入 ngOnInit 方法中

    export class ProfileComponent implements OnInit {
      network$: any;
      profiles$: Observable<Profile[]>
      constructor(private store:Store<NetAlertState>) { }
    
      ngOnInit() {
        this.store.dispatch({ type: '[Profile Component] getAllProfiles' });
        this.store.dispatch({ type: '[Profile Component] getNetworkInfo' });
        this.network$ =  this.store.select(a=>a.NetworkInfo);
        this.profiles$ = this.store.pipe(select(state => state.Profiles));
      }
    }
    

    也尝试使用管道运算符

    【讨论】:

    • @OrYaacov 再次检查我的答案
    猜你喜欢
    • 1970-01-01
    • 2020-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-13
    • 2021-01-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多