gertqin / vuex-class-modules

Typescript class decorators for vuex modules
MIT License
194 stars 20 forks source link

Persist state of vuex store #24

Open TheSimpleZ opened 4 years ago

TheSimpleZ commented 4 years ago

Hello!

I'm using your library inside an electron app built with Vue. I need to persist the state of the vuex store. To achieve this i tried saving the vuex state to a json file, using a vuex plugin. However, when i restore the state, on app launch, i get an error saying Error: [vuex-class-module]: A module with name 'myModule' already exists..

I'm pretty sure the Error originates from here: https://github.com/gertqin/vuex-class-modules/blob/61b18a42b9e3dc09e7484b939b527363bcc1d688/src/module-factory.ts#L173

I'm mainly wondering what the best way to solve this problem is. I was looking through the vuex docs and found a flag for registerModule called preserveState, do you think it would solve the problem if it was passed at registration time?

bodograumann commented 4 years ago

That is in interesting question.

Which vuex plugin are you using to save and restore the state? Maybe you could show some example code?

TheSimpleZ commented 4 years ago

Absolutly! I tried using https://github.com/vue-electron/vuex-electron, but when i got the error i tried simplifying the code. So i wrote my own plugin which depends on https://github.com/sindresorhus/electron-store (flatted is a JSON (de)serializer which can handle circular references). Still got the same error. Then i realized the error was originating from this library. My code looks like this (written in Typescript):

import { Store } from 'vuex'
import ElectronStore from 'electron-store'
import { stringify, parse } from 'flatted'

const STORAGE_NAME = 'vuex'
const STORAGE_KEY = 'state'

export default function persistState<T>(store: Store<T>) {
  const eStore = new ElectronStore<T>({
    name: STORAGE_NAME,
    serialize: v => stringify(v),
    deserialize: parse,
  })

  const initialState = eStore.get(STORAGE_KEY)
  if (initialState) {
    store.replaceState(initialState)
  }

  store.subscribe((m, s) => {
    eStore.set(STORAGE_KEY, s)
  })
}

You can see more complete code samples in my repo here: https://github.com/TheSimpleZ/TerraCAD/tree/preferences/src/store

bodograumann commented 4 years ago

Indeed the way you set the state conflicts with how we register the module. There is the possibility of using HMR in https://github.com/gertqin/vuex-class-modules/blob/61b18a42b9e3dc09e7484b939b527363bcc1d688/src/module-factory.ts#L166-L172 but I would guess that that also overwrites the state.

So there are two options here:

TheSimpleZ commented 4 years ago

I tried using HMR (i assume it's simply putting plugins: [new webpack.HotModuleReplacementPlugin()], in my webpack.config.js). Didn't work.

Assuming I would like to use a pre-made plugin your first option won't work. I will try to see if i can come up with some nice way of implementing persistence after my modules have been registered.

Do you think it would be a lot of work implementing the second option? I imagine you could simply add another parameter for preserveState to the RegisterOptions interface and pass it along to the registerModule function.

bodograumann commented 4 years ago

I expanded the above code citation. As you see HMR means using the hotUpdate method from vuex.

Adding another method would probably not be hard to code, but we would have to think about whether we want to support / encourage that usage. Also there are other situations to consider. Just imagine, that there are already mutations, actions, etc. registered in the module.

TheSimpleZ commented 4 years ago

I see...

Well it would be great if you would consider adding support for state persistence. I don't feel like I know enough about Vuex to be able to identify the side-effects it might cause.

Until then, I'll look into alternative solutions. Thanks for your help :)

0x6F72656F73 commented 3 years ago

Any updates? This library is solid and It would be great to have state persistence.

BonBonSlick commented 2 years ago

@bodograumann @0x6F72656F73 Any updates? State persisted only before page reloaded. After that it throws error

 vue-devtools  Detected Vue v2.6.14 
 {FormWithVerification: accessor {SET_STEP: ...}
 {testVal_1: 'original_val'} // call getter
// call action with mutation within
 {testVal_1: 'mutated_val'} // call getter

// RELOAD PAGE OR REOPEN TAB (SPA)

 {FormWithVerification: accessor {SET_STEP: ...} // same
 {testVal_1: undefined} // call getter
// call action with mutation within throws
unknown action type: FormWithVerificationModule/changeVal
 {testVal_1: undefined} // call getter

I also see state in dev tools, BUT, getters are removed / actions. Sate not persisted nor dynamic modules registered again. Its like they were loaded only on the first page load.