I am trying to get my data using selectors in me app.component.ts. I do this by dispatching an action when loading the page that will catch an effect and in that way using a service, address me api. The problem is that when loading the page, my Observable streams from my selectors are null, giving me an 'cannot read properties of undefiend' error. Also my on the page there is written 'null'. In the redux dev tools i can see the correct data, so the problem is not the api. Below you can find my different files. Thanks in advance for the help.
app.component.html
{{ heroes$ | async | json }} // null when page loads
app.component.ts
heroes$: Observable<SuperHeroInterface[] | null> = new Observable<SuperHeroInterface[] | null>();();
ngOnInit(): void {
this.fetchData();
this.initializeValues();
}
fetchData() {
this.store.dispatch(getSuperHeroAction())
}
initializeValues(): void {
this.heroes$ = this.store.pipe(select(dataSuperHeroSelector)) // something here is wrong
}
actions.ts
export const getSuperHeroAction = createAction(
ActionTypes.GET_SUPER_HERO
)
reducers.ts
const initialState: SuperHeroStateInterface = {
heroes: null,
}
const superHeroesReducer = createReducer(
initialState,
// Get Super Hero
on(getSuperHeroAction, (state): SuperHeroStateInterface => ({
...state,
})),
on(getSuperHeroActionSuccess, (state, action): SuperHeroStateInterface => ({
...state,
heroes: action.heroes
})),
on(getSuperHeroActionFailure, (state, action): SuperHeroStateInterface => ({
...state,
})),
)
selectors.ts
export const superHeroFeatureSelector = createFeatureSelector<SuperHeroStateInterface>('superHeroes')
export const dataSuperHeroSelector = createSelector(
superHeroFeatureSelector,
(superHeroState: SuperHeroStateInterface) => superHeroState.heroes
)
effects.ts
getSuperHeroes$ = createEffect(() => this.actions$.pipe(
ofType(getSuperHeroAction),
exhaustMap(() => {
// wrapping the success action to an observable with pipe rxjs operator
return this.superHeroService.getSuperHeroes().pipe(
map((heroes: SuperHeroInterface[]) => {
return getSuperHeroActionSuccess({ heroes })
}),
catchError((errorResponse: HttpErrorResponse) => {
// wrapping the failure action to an observable with of rxjs operator
return of(getSuperHeroActionFailure({ error: errorResponse.error.errors })
)
})
)
})
)
)
SuperHeroClass
export class SuperHeroInterface {
id?: number;
name: string = "";
firstName: string = "";
lastName: string = "";
place: string = "";
}
SuperHeroStateInterface
export interface SuperHeroStateInterface {
heroes: SuperHeroInterface[] | null;
}
I don't see how the state is registered.
Make sure that the reducer is coupled to the superHeroes
key.
You can verify this by looking at the global state tree with the redux devtools.
Also, you could make use of new APIs to make this easier - https://timdeschryver.dev/blog/you-should-take-advantage-of-the-improved-ngrx-apis