koque
koque

Reputation: 2256

Why is NgRx not producing the expected state?

I have imported NgRx into my application:

imports: [
    StoreModule.forRoot(reducers, {})    
 ],

My reducers are registered in /ngrx/reducers/index.ts as shown:

import { ActionReducerMap } from "@ngrx/store";
import { HeroReducers } from "../home/hero/hero.reducers";

export interface State {};

export const reducers: ActionReducerMap <State> = {
    heroReducers:HeroReducers
}

HeroReducer is shown here:

import { createReducer, on } from '@ngrx/store';
import * as heroActions from "./hero.actions";

const initialState = {
  heroSlides: [
    {
      img: "Screenshot from 2024-01-20 12-38-48.png",
      status: "active"
    },
  ]
}

export const HeroReducers = createReducer(initialState,
on(heroActions.StoreHero, (state, action) => { 
  console.log('Storesubjects.subjects', action)   
  return {
    ...state,
    // subjects: action.subjects,
  };
}),
)

The action file for the reducer is shown here:

import { createAction, props } from "@ngrx/store";

  export const StoreHero = createAction(
    '[Store Hero] Store Hero'
  )

I inject the store in my component as shown here:

constructor(
    private store:Store<{heroReducers}>
  ) {}

In ngOnInit of my component, I subscribe to the reducer as shown. I also dispatch a call to the reducer.

ngOnInit() {
    this.subscribeToReduxStores();  
    this.store.dispatch(StoreHero());
}

  private subscribeToReduxStores = () => {
    const hero$ = this.store.select((state) => {   
      console.log('state', state)   
      return state
   })

    hero$.subscribe(hero => {      
      // this.hero = hero;    
      console.log('hero', hero)                    
   })
 }

I get the following results of the console.log calls:

state {}
hero {}
state {}

The state is an empty object and does not contain the heroSlides array of the initialState of the HeroReducers.

Upvotes: 0

Views: 57

Answers (1)

Andres2142
Andres2142

Reputation: 2907

A couple of observations that potentially fix your issue.

Your initialState for HeroesReducer does not have a type defined. You can define what shape is going to have this particular heroes slice like the following:

heroes.reducer.ts

export interface HeroState {
  slides: { img: string; status: string}[];
}

const initialState: HeroState = {
  slides: [];
}

export const HeroesReducers(initialState, ...);

Where you have your ActionReducerMap, there is an empty interface called State, I feel like you could use that one in order to wrap the whole store slices definition, like the following:

import {HeroState} from '../heroes/heroes.reducer.ts';

export interface State {
  heroes: HeroState; 
  villains: VillainsState; // you could add more slices here
  biography: BiographyState; // you could add more slices here
}

Having that, now you can inject your store with the proper data type as:

some.component.ts

import {State} from '../interfaces/store.interface.ts'; // this is just an example

  constructor(private store: Store<State>) {}

I feel like your current code fails to know what the store has since you are defining the store dataType as Store<{heroReducers}>, from where are you taking this heroReducers? Also, make sure to use redux dev tools browser extension to see what you have in the store initially, validating if the heroes slice is defined and also to see every action triggered and monitor what happens with the data.

Additionally, the callback function for selecting data from the store should be defined in the proper selectors file using createSelector function, for example, heroes.selectors.ts rather than having that logic in your component.

heroes.selectors.ts

export const selectHeroes = createSelector(state => state.heroes);

For more information about selectors, I recommend reading the official docs

Upvotes: 0

Related Questions