prazdevs / pinia-plugin-persistedstate

đź’ľ Configurable persistence and rehydration of Pinia stores.
https://prazdevs.github.io/pinia-plugin-persistedstate/
MIT License
2.13k stars 121 forks source link

unable to force hydration from afterRestore hook #161

Closed eltorio closed 1 year ago

eltorio commented 1 year ago

Describe the bug

I try to force hydration based on a timestamp in afterRestore hook

For reproducting:

git clone https://github.com/highcanfly-club/pinia-hydration-test.git
cd pinia-hydration-test
npm i
npm run dev

Launch a browser on the dev port (probably http://127.0.0.1:5173), open the console and refresh the page I get:

Uncaught TypeError: ctx.store.$hydrate is not a function
    at afterRestore (main.ts:25:63)
    at index.mjs:94:39
    at Array.forEach (<anonymous>)
    at index.mjs:90:18
    at pinia.mjs:1634:48
    at EffectScope.run (reactivity.esm-bundler.js:34:24)
    at pinia.mjs:1634:38
    at Array.forEach (<anonymous>)
    at createSetupStore (pinia.mjs:1631:14)
    at createOptionsStore (pinia.mjs:1224:13)

The repo was basically created with:

npm create vite@latest pinia-hydration-test --template vue
cd pinia-hydration-test
npx npm-check-updates -u
npm i --save pinia pinia-plugin-persistedstate
vi src/main.ts

only main.ts was modified https://github.com/highcanfly-club/pinia-hydration-test/blob/51919cabac6d1ac317ca07aebc369182b56a9779/src/main.ts#L4 store was defined like this

const useStore = defineStore("store", {
  state: () => {
    return {
      storeTimestamp: 0,
    };
  },
  persist: {
    storage: localStorage,
    paths: ["storeTimestamp"],
    afterRestore: (ctx) => {
        // const store = useStore()
        // store.$hydrate()
        console.log('force hydration');
        (ctx.store as Store<"store",{storeTimestamp:number}>).$hydrate()
    },
  },
});

const store = useStore()

uncommenting the two commented lines makes the same result

Reproduction

https://github.com/highcanfly-club/pinia-hydration-test.git

System Info

System:
    OS: macOS 13.2
    CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 373.31 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.19.0 - /usr/local/bin/node
    Yarn: 1.22.18 - /usr/local/bin/yarn
    npm: 8.19.3 - /usr/local/bin/npm
  Browsers:
    Brave Browser: 108.1.46.144
    Chrome: 108.0.5359.124
    Edge: 108.0.1462.54
    Firefox: 108.0
    Safari: 16.2

Used Package Manager

npm

Validations

prazdevs commented 1 year ago

I looked into the code and did some tests. It's caused by the initial rehydration (and hooks) being done before the $hydrate and $persist functions are bound to the store.

Im just sceptical about the use of these methods in hooks ?

However the error of the methods being undefined at hook call time can be fixed. Its just kinda dangerous because you risk running infinite recursion if you dont specify { runHooks: false }

eltorio commented 1 year ago

Dear Praz, thank you for your answer, you can be sceptical ! But this is only a small code for reproducing the $hydrate call. Let me explain my objective: I have a store filled during navigation by remote requests to some remote URLs, this is time consuming and since I need to proxy the request for CORS, it is server consuming. Today if my store is already filled I return the store content and there is no remote request nor proxy request… My store is a sort of cache. No problem with the expiration of datas because while the user closes its browser or hits refresh the store is deleted and it will be refilled…

But I'd like to make my store partially persistent for 7 days, so I added some timestamps and want to check in afterRestore if I need to reconstruct the cache. If nedded I'd like to delete the localStorage and next run $hydrate() for having a clean "persistence ready" store.

That's why I said that is not necessary a "bug" but probably a misunderstand Ronan

eltorio commented 1 year ago

my current workaround is ugly: In beforeRestore I manually deserialize the localStorage keys for the stores, retrieve all the timestamps and if necessary issue some localStorage.removeItem('storeId') It works…