Store: @ngxs/hmr-plugin does not properly restore state

Created on 13 Jun 2019  路  6Comments  路  Source: ngxs/store

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report  
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => https://github.com/ngxs/store/blob/master/CONTRIBUTING.md
[ ] Other... Please describe:

Current behavior

If I use HMR along @ngxs/hmr-plugin, and have in the store data instanciated from a class, after the state restoration that comes with the hot module reloading, the type information and methods of my stored data are lost.

This is due to the fact that the state data is serialized/deserialized from session storage, but I really don't get why? I saw a new commit for the upcoming v4 version that removes the session storage, but does seems to do worse by deep cloning with JSON.parse(JSON.stringify(state)) the state during init, which seems worse to me at it affects even more that HMR use cases 馃槺

Expected behavior

I expected the @ngxs/hmr-plugin to restore the state exactly as it was before the hot module reload.

FWIW, I managed to work around this by not using the plugin and doing the same thing myself, with only few lines of code, instead of hmr(module, bootstrap) I use:

  let ngModule: NgModuleRef<any>;
  module.hot.accept();
  const dataTransfer: any = module.hot.data; // get data from destroyed module

  bootstrap()
    .then(mod => {
      ngModule = mod;
      // restore previous state
      if (dataTransfer.snapshot) {
        const store: Store = ngModule.injector.get(Store);
        store.reset(dataTransfer.snapshot);
        console.info('[HMR] Store restored');
      }
    })
    .catch(err => console.warn(err));

  module.hot.dispose((data: any) => {
    // save current state before disposing
    const store: Store = ngModule.injector.get(Store);
    data.snapshot = store.snapshot();

    const appRef: ApplicationRef = ngModule.injector.get(ApplicationRef);
    const elements = appRef.components.map(c => c.location.nativeElement);
    const makeVisible = createNewHosts(elements);
    ngModule.destroy();
    makeVisible();
  });

Minimal reproduction of the problem with instructions

What is the motivation / use case for changing the behavior?

I want to be able to store class instances in the store, and have it properly restored after HMR reload.

Environment


Libs:
- @angular/core version: 7.3.9
- @ngxs/store version: 3.4.3


Browser:
- [x] Chrome (desktop) version 74
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX


Others:

plugins

All 6 comments

I want to be able to store class instances in the store

Read Mark's comment please

@sinedied The current version of the hmr plugin does not work as expected, so we planned to release a fixed version. But given your comment, I think we can fix some points.

Thanks! Looking forward to v4 :smiley:

It will be available in version 3.5. Just don't use defaultsState in forRoot;

Released in 3.5.0

Was this page helpful?
0 / 5 - 0 ratings