store
store copied to clipboard
Subscription lost after pushing page with NavController
This is a...
- [ ] feature request
- [x] bug report
- [ ] usage question
What toolchain are you using for transpilation/bundling?
- [ ] @angular/cli
- [ ] Custom @ngTools/webpack
- [ ] Raw
ngc - [ ] SystemJS
- [ ] Rollup
- [x] Other (Ionic 3)
Environment
NodeJS Version: 9.3.0 Typescript Version: 2.4.2 Angular Version: 5.0.3 @angular-redux/store version: 7.1.0 @angular/cli version: (if applicable) OS: Windows 10
Expected Behaviour:
Subcriptions should work after moving to an other page and comming back again.
Actual Behaviour:
After pushing from the page with one select decorator @select(['patients', 'items']) to another page without one and then coming back with the back button, our observable does not get fired anymore. All subscriptions stopped working. When we start adding new patients to the state they are not popping up in the ui anymore. All new objects are going through the reducer and the state gets changed properly. But our items$ property does not get updated.
Stack Trace/Error Message:
No.
in patient-list.ts
export class PatientListPage {
@select(['patients', 'items'])
items$: Observable<IPatient[]>;
}
in store.create.ts
import { compose, createStore } from 'redux';
import { IClientDataSyncService } from '../services/contracts/sync/clientDataSync';
import { IAppState } from './store.model';
import { rootReducer } from './store.reducers';
export const configureStore = (clientDataSync: IClientDataSyncService, preloadedState?: IAppState) => {
return createStore<IAppState>(
rootReducer,
preloadedState,
);
};
in store.module.ts
import { IClientDataSyncService, TYPE } from '../services/contracts/sync/clientDataSync';
import { lazyInject } from '../utils/ioc/ioc';
import { configureStore } from './store.create';
import { IAppState } from './store.model';
@NgModule({
imports: [NgReduxModule /*NgReduxRouterModule*/],
})
export class StoreModule {
@lazyInject(TYPE.DataSyncService) private dataSyncService: IClientDataSyncService;
constructor(private store: NgRedux<IAppState>) {
store.provideStore(configureStore(this.dataSyncService));
provideReduxForms(store);
}
}
in store.reducers.ts
import { composeReducers, defaultFormReducer } from '@angular-redux/form';
import { combineReducers, Reducer } from 'redux';
import { reducer as auditReducer } from '../components/swodoc/_reducers/audit.reducer';
import { reducer as templateReducer } from '../components/swodoc/_reducers/template.reducer';
import { reducer as orderReducer } from '../pages/order/order.reducer';
import { reducer as selectedPatientReducer } from '../pages/patient/patient-edit/edit-patient.reducer';
import { reducer as patientsReducer } from '../pages/patient/patients.reducer';
import { IAppState } from './store.model';
// Define the global store shape by combining our application's
// reducers together into a given structure.
export const rootReducer: Reducer<IAppState> = composeReducers<IAppState>(
defaultFormReducer(),
combineReducers({
patients: patientsReducer,
orders: orderReducer,
patientSelection: selectedPatientReducer,
audits: auditReducer,
templates: templateReducer,
// router: routerReducer,
}),
);
in patient.reducer.ts
import { reducerWithInitialState } from 'typescript-fsa-reducers';
import { IPatient } from '../../models/contracts/patient';
import { createPatient, deletePatient, editPatient } from './patients.actions';
import { IPatientState } from './patients.model';
const initialState: IPatientState = {
isFetching: false,
items: [],
};
const createPatientHandler = (state: IPatientState, patient: IPatient): IPatientState => {
if (state.items.findIndex(x => x._id === patient._id) === -1) {
return {
...state,
items: [...state.items, patient],
};
}
return state;
};
const editPatientHandler = (state: IPatientState, patient: IPatient): IPatientState => {
const newstate = {
...state,
items: state.items.map(item => (item._id === patient._id ? { ...item, ...patient } : item)),
};
return newstate;
};
const deletePatientHandler = (state: IPatientState, patient: IPatient): IPatientState => {
const newstate = {
...state,
items: state.items.filter(item => item._id !== patient._id),
};
return newstate;
};
export const reducer = reducerWithInitialState(initialState)
.case(createPatient, createPatientHandler)
.case(editPatient, editPatientHandler)
.case(deletePatient, deletePatientHandler);
We now know why this is happening. When we use lazy loading for pages with NavController from Ionic like this:
this.navCtrl.push('PatientDetailPage', { item: patient });
then our store module where we instantiate the store is loaded again by angulars bootstrapping process. This is probably a bug in angular 5?
Same problem here, with ng4 and ngcli