Following some examples, I'm trying to manage the state of a sideBar component (open/closed). I have defined some interfaces to manage my state objects:
export interface AppState {
readonly layoutState: LayoutState;
}
export interface LayoutState {
sideBarOpen: boolean;
}
I have a local variable in my Component that implements the LayoutState interface: layout: LayoutState;
I subscribe to my state in ngOnInit
:
this.store.subscribe(appState => {
this.layout = appState.layoutState;
// (5)
});
I have a button in my UI that calls a function that contains this line: this.toggleSideNav(this.layout.sideBarOpen);
toggleSideNav looks like this:
toggleSideNav(currentState: boolean) {
this.store.dispatch(new LayoutActions.ToggleSidebarAction(currentState)); // (1)
}
Here is my effect:
@Effect()
toggleSidebar$ = this.actions$
.ofType(LayoutActions.TOGGLE_SIDEBAR)
.switchMap((action: ToggleSidebarAction) =>
this.layoutService.toggleSidebar(action.payload) // (2)
)
.map((layoutState: LayoutState) => {
// (4)
return new LayoutActions.ToggleSidebarSuccessAction(layoutState);
});
Here is the layoutService.toggleSidebar
function:
toggleSidebar(currentState: boolean): Observable<LayoutState> {
const rv = {
sideBarOpen: !currentState
};
// (3)
return Observable.of(rv);
}
Here is what I see when debugging. At position:
(1) - currentState
is false
- as expected
(2) - action.payload
is false
- as expected
(3) - rv
is {sideBarOpen: true}
- as expected
(4) - layoutState
is {sideBarOpen: true}
- as expected
(5) - this.layout
is {sideBarOpen: false}
- !!
Why does the state get "lost" between (4) and (5)?
I was forgetting that after the Effect, it goes to the Reducer. My Reducer only had this:
switch (action.type) {
case Actions.LOAD_LAYOUT_SUCCESS:
return action.payload;
default:
return state;
}
I had to add a case for the TOGGLE_SIDEBAR_SUCCESS
message to send the new state (contained in the payload):
switch (action.type) {
case Actions.LOAD_LAYOUT_SUCCESS:
return action.payload;
case Actions.TOGGLE_SIDEBAR_SUCCESS: <--
return action.payload; <--
default:
return state;
}
Before adding that, the reducer was falling through to the default case, and returning state
, which is the old state.