我知道这是死灵法术;P 但对于一些人来说,这仍然可能有用。
TL;DR
你错过了angular-class HMR的一个很重要的部分,那就是metareducer用于设置完整状态。
以下是我如何使用HMR的实现方式,其中包含了一个示例链接
https://github.com/gdi2290/angular-hmr
Metareducer
首先,您需要一个metareducer来处理设置整个状态的操作。
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;
当为NgModule注册StoreModule.forRoot时,请记得注册该元减数数组。
StoreModule.forRoot(reducers, { metaReducers })
AppModule
对于 AppModule,您需要定义 hmrOnInit、hmrOnDestroy 和 hmrAfterDestroy 方法。
- hmrOnInit 加载状态
- hmrOnDestroy 写入状态(请注意,ngrx store.take(1) 实际上是同步的,这在 ngrx 的 github 问题中有提到,目前无法找到具体位置)。
- hmrAfterDestroy 清理现有组件元素
export class AppModule {
constructor(
private appRef: ApplicationRef,
private store: Store<fromRoot.State>
) { }
public hmrOnInit(store) {
if (!store || !store.state) {
return;
}
this.store.dispatch({ type: 'SET_ROOT_STATE', payload: store.state });
if ('restoreInputValues' in store) {
const restoreInputValues = store.restoreInputValues;
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;
store.disposeOldHosts = createNewHosts(cmpLocation);
store.restoreInputValues = createInputTransfer();
removeNgStyles();
}
public hmrAfterDestroy(store) {
store.disposeOldHosts();
delete store.disposeOldHosts;
}
}
更多详细信息请参见https://github.com/gdi2290/angular-hmr
。