I am currently using an angular-cli project(1.0.0-beta.25.5) with ngrx to manage state. I have followed this article and managed to get hot module replacement working however I have not found a way to maintain state when this happens.
I have seen the following but have been unable to get anything working or take inspiration:
https://github.com/AngularClass/angular2-hmr (think you need access to webpack config to add loader)
Angular 2 : Thoughs about HMR and @ngrx/store (tried the get__HMR__state but didn't work for me)
Does anyone have any ideas or suggestions on how to approach this? I wish to remain using the cli so need to find a way of integrating with this.
Edit: Found someone with the same issue here as well https://github.com/ngrx/store/issues/311
I know this is necromancy ;P But for some this still might be useful.
What you missed from angular-class HMR was quite likely metareducer for setting the complete state.
Below is how I implemented HMR with link to example from which I derived this https://github.com/gdi2290/angular-hmr
First you need a metareducer to handle setting whole state.
// make sure you export for AoT
export function stateSetter(reducer: ActionReducer<any>): ActionReducer<any> {
return function(state: any, action: any) {
if (action.type === 'SET_ROOT_STATE') {
return action.payload;
}
return reducer(state, action);
};
}
let _metaReducers: MetaReducer<fromRoot.State, any>[] = [];
if (environment.hmr) {
_metaReducers = [stateSetter];
}
export const metaReducers = _metaReducers;
When registering StoreModule.forRoot for NgModule remember to register that metareducer array.
StoreModule.forRoot(reducers, { metaReducers })
For the AppModule you need to define hmrOnInit , hmrOnDestroy & hmrAfterDestroy methods.
export class AppModule {
constructor(
private appRef: ApplicationRef,
private store: Store<fromRoot.State>
) { }
public hmrOnInit(store) {
if (!store || !store.state) {
return;
}
// restore state
this.store.dispatch({ type: 'SET_ROOT_STATE', payload: store.state });
// restore input values
if ('restoreInputValues' in store) {
const restoreInputValues = store.restoreInputValues;
// this isn't clean but gets the job done in development
setTimeout(restoreInputValues);
}
this.appRef.tick();
Object.keys(store).forEach(prop => delete store[prop]);
}
public hmrOnDestroy(store) {
const cmpLocation = this.appRef.components.map(
cmp => cmp.location.nativeElement
);
let currentState: fromRoot.State;
this.store.take(1).subscribe(state => (currentState = state));
store.state = currentState;
// recreate elements
store.disposeOldHosts = createNewHosts(cmpLocation);
// save input values
store.restoreInputValues = createInputTransfer();
// remove styles
removeNgStyles();
}
public hmrAfterDestroy(store) {
// display new elements
store.disposeOldHosts();
delete store.disposeOldHosts;
}
}
For more specific information see https://github.com/gdi2290/angular-hmr
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