I migrated to Ngrx Store v4.1.1 (+ Angular5) according to their example-app. Everything runs fine as before but one SubStore. That SubStore's state contains a Map which is changed. But changes to this Map are somehow not recognized.
Working Plunker can be found here: https://plnkr.co/edit/2Z77Cq?p=preview Detailed code below
My NgModule looks like that:
import {reducers} from './reducers';
@NgModule({
imports: [
BrowserModule,
StoreModule.forRoot(reducers)
],
declarations: [ App ],
bootstrap: [ App ],
providers: [Service]
})
My reducers look like that:
import {
ActionReducerMap,
createSelector,
createFeatureSelector,
} from '@ngrx/store';
import * as character from './character.reducer';
export interface State {
character: character.State;
}
export const reducers: ActionReducerMap<State> = {
character: character.reducer,
};
/** Character **/
export const getCharacterState = createFeatureSelector<character.State>('character');
export const getCharacter = createSelector(
getCharacterState,
character.getCharacter
);
The SubStore Reducer contains the following code:
import { Character, Item } from './models';
import * as character from './character';
export interface State {
character: Character;
}
export const initialState: State = {
character: null,
};
export function reducer(state = initialState, action:character.Actions): State {
switch (action.type) {
case character.INIT_CHARACTER:
const char: Character = action.payload;
state.character = char;
console.log('init char', char);
return Object.assign({}, state);
case character.EQUIP_ITEM:
const eqItem: Item = action.payload;
state.character.wardrobeItemIds.set(eqItem.part, eqItem.id);
console.log('eq ITEMMM', eqItem, state.character.wardrobeItemIds);
return Object.assign({}, state);
default:
return state;
}
}
export const getCharacter = (state: State) => state.character;
With the corresponding Actions being:
import { Action } from '@ngrx/store';
import { Character, Item } from './models';
export const INIT_CHARACTER = '[Character] Initialized Character';
export const EQUIP_ITEM = '[Character] Equipped Item';
export class InitCharacter implements Action {
readonly type = INIT_CHARACTER;
constructor(public payload: Character) {}
}
export class EqItem implements Action {
readonly type = EQUIP_ITEM;
constructor(public payload: Item) {}
}
export type Actions =
InitCharacter |
EqItem;
Now I initialize the SubStore with a new Character in my Service:
import { Injectable } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import {Character, Item} from './models';
import * as fromRoot from './reducers.ts';
import * as CharacterAction from './character.ts';
@Injectable()
export class Service {
character$: Observable<Character>;
constructor(
private store: Store<fromRoot.State>
) {
// listen to the store
this.character$ = this.store.select(fromRoot.getCharacter);
this.character$.subscribe(
(state: any) => console.log('char store triggered. State:', state)
);
// init the wardrobeItemIds Map
const wardrobeItemIds = new Map<string, string>();
wardrobeItemIds.set('part1', 'anyId');
// init the character (this is just a dummy)
let newCharacter: Character = {
baseType: 'anyString',
skinItemIds: [
'string1',
'string2'
],
wardrobeItemIds: wardrobeItemIds
}
this.store.dispatch(new CharacterAction.InitCharacter(newCharacter));
}
addItem(part: string): void {
// add rnd item of given part
const item: EquipItem = {
id: Math.random().toString(),
part: part,
}
this.store.dispatch(new CharacterAction.EqItem(item));
}
}
This causes my Subscription inside the same Service
this.character$.subscribe(
(state: any) => console.log('char store triggered. State:', state)
);
to log the character, which is fine, because it changed from null to the character Object.
Now if I call addItem()
which calls this.store.dispatch(new CharacterAction.EqItem(item));
which should add an item to the Map state.character.wardrobeItemIds
.
This should cause the Store Observable to fire again and the subscription should log the changed character. But somehow nothing happens. Already checked that the reducer receives the Action properly.
Not sure if this just my stupidity or some kind of bug?
Thx in advance Tobi
It seems that @ngrx/entity is the intended solution for more complex data structures in the store. The use of Map will trigger the new runtime checks if you turn them on, as they are neither immutable not serializable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With