ngrx / store

RxJS powered state management for Angular applications, inspired by Redux
MIT License
3.9k stars 311 forks source link

works in dev mode, but in with prod or aot set the state is always empty #409

Closed hakonamatata closed 7 years ago

hakonamatata commented 7 years ago

This is similar to this closed issue: https://github.com/ngrx/store/issues/401

But I cannot quite get it to work.

Upgraded to Angular ^4.0.0 and latest packages generated by Angular Cli

When I run the app with ng serve, it works, but as soon as I add --prodor--aot, state is not saved

I can see that the actions and payloads are executed and sent in redux devtools. But the state remain empty...

I have several reducers stored here:

root.reducer

import { compose } from "@ngrx/core";
import { combineReducers } from "@ngrx/store";

// reducers
import { user } from "app/_reducers/user.reducer";
import { notifications } from "app/_reducers/notification.reducer";
import { intro } from "app/_reducers/intro.reducer";
import { statistics } from "app/_reducers/statistics.reducer";
import { chat } from "app/_reducers/chat.reducer";

export const reducers = {
    user, notifications, intro, statistics, event, chat
};

Here is an example:

user.reducer

// tslint:disable:semicolon

import { Action, combineReducers } from '@ngrx/store';

import { UserInfo } from 'app/_models/nimbus/user-info';
import { compose } from "@ngrx/core";

// user actions
export const USER_LOGIN = 'USER_LOGIN'
export const USER_LOGOUT = 'USER_LOGOUT'
export const USER_UPDATE_JWT = 'USER_UPDATE_JWT'
export const USER_SET_USERINFO = 'USER_SET_USERINFO'

export class UserPayload {

    public loggedIn: boolean;
    public jwt: string;
    public userInfo: UserInfo;

    public constructor(data: any = {}) {
        this.loggedIn = data.loggedIn
        this.jwt = data.jwt || ''
        this.userInfo = data.userInfo
    }
}

const makeInitialState = () => {
    return new UserPayload({
        loggedIn: false
    })
}

export const user = (state = makeInitialState(), action: Action) => {

    switch (action.type) {
        case USER_LOGIN:
            return new UserPayload({
                loggedIn: true,
                jwt: action.payload.jwt,
                userInfo: state.userInfo
            })
        case USER_SET_USERINFO:
            return new UserPayload({
                loggedIn: state.loggedIn,
                jwt: state.jwt,
                userInfo: action.payload.userInfo
            })
        case USER_UPDATE_JWT:
            return new UserPayload({
                loggedIn: state.loggedIn,
                jwt: action.payload.jwt,
                userInfo: state.userInfo

            })
        case USER_LOGOUT:
            return makeInitialState()
        default:
            return state
    }
}

app.module


    StoreModule.provideStore(reducers),
    StoreDevtoolsModule.instrumentOnlyWithExtension(),
hakonamatata commented 7 years ago

Was able to fix it, had to refactor the application to look more like the example.

Changed root.reducer.ts to index.ts and made these changes:

import { compose } from "@ngrx/core";
import { combineReducers, ActionReducer } from "@ngrx/store";
import { storeFreeze } from 'ngrx-store-freeze';

import { environment } from "environments/environment";
import { NotificationList } from "app/_models/bspec/reader/notification-list";

import * as fromRouter from '@ngrx/router-store';
import * as fromUser from "app/_reducers/user.reducer";
import * as fromNotifications from "app/_reducers/notification.reducer";

// reducers
// import { notifications } from "app/_reducers/notification.reducer";
// import { intro } from "app/_reducers/intro.reducer";
// import { statistics } from "app/_reducers/statistics.reducer";
// import { chat } from "app/_reducers/chat.reducer";

export interface State {
  // search: fromSearch.State;
  // books: fromBooks.State;
  // collection: fromCollection.State;
  // layout: fromLayout.State;
  router: fromRouter.RouterState;
  user: fromUser.UserPayload;
  notifications: NotificationList;
}

// export const reducers = {
//   user, notifications, intro, statistics, event, chat
// };

const reducers = {
  // search: fromSearch.reducer,
  // books: fromBooks.reducer,
  // collection: fromCollection.reducer,
  // layout: fromLayout.reducer,
  router: fromRouter.routerReducer,
  user: fromUser.reducer,
  notifications: fromNotifications.reducer
};

const developmentReducer: ActionReducer<State> = compose(storeFreeze, combineReducers)(reducers);
const productionReducer: ActionReducer<State> = combineReducers(reducers);

export function reducer(state: any, action: any) {
  if (environment.production) {
    return productionReducer(state, action);
  } else {
    return developmentReducer(state, action);
  }
}
dolanmiu commented 7 years ago

@hakonamatata I am having the same issue as you, could you point to me where the example is?

hakonamatata commented 7 years ago

sure @dolanmiu

I used this as an example:

https://github.com/ngrx/example-app