soc221b / pinia-plugin-persistedstate-2

Persist and rehydrate your Pinia state between page reloads.
https://www.npmjs.com/package/pinia-plugin-persistedstate-2
MIT License
91 stars 8 forks source link

Add $hydrate method to the store #228

Closed SeekerOfTrueCode closed 1 year ago

SeekerOfTrueCode commented 1 year ago

Describe the solution you'd like

I propose exposing / adding $hydrate method to the store to allow manual trigger of hydration. This would fetch data from storage and replace the current state with it.

This would allow the user to freely replace the current pinia state with the state of the store upon some events or if data on the store is expected to change outside of the pinia's influence - rare but real use cases. I can also see how it could be useful to someone who uses micro-frontends approach.

Great for synchronization of changes between the apps

Is your feature request related to a problem? Please describe.

I am currently working on browser extension. Developing one requires creation of multiple Vue apps (one for popup, one for background, one for content-scripts, one for options page etc.). Because each app has it's own pinia instance it's hard to share the state between all of the apps. My solution is to use "browser.storage.local" (similar to localStorage but for browser extensions) which allows me to store that state and access it across those apps in combination with this plugin for pinia. All of that gave me partial success, because indeed whenever I open my popup app and make some changes to the store and then for example open the options page those changes will be there (because upon options app creation pinia plugin will load the state from the "browser.storage.local").

The problem is if I open both popup and options apps, changing something in one doesn't propagate the changes to the other (because data from storage are loaded only upon creation and there is no mechanism for watching the storage to update pinia store). I need the changes to propagate live, so I can observe them in all apps without the need to close and open the app to see them.

If $hydrate method existed inside the store, I could send the messages between those apps upon "setItem" trigger and listen for those messages to execute $hydrate method and load the new state.

Example: storage definition in options app:

(...)
setItem: async (key, value) => {
        await browser.storage.local.set({ [key]: value })
        const tabs = await browser.tabs.query({ active: true, currentWindow: true })
        tabs.filter(tab => tab.id != null).forEach(tab => sendMessage('refresh-store', null, { context: 'content-script', tabId: tab.id! }))
}
(...)

storage inside content-script app:

(...)
const myStore= useMyStore()
onMessage('refresh-store', () => {
    myStore.$hydrate() // whenever other application send an event, state will be replaced to sync the changes
})
(...)

Describe alternatives you've considered

I could probably write a custom plugin which will replace the pinia state with state of the storage but I don't see a reason why it shouldn't be native solution for this plugin. The problem with directly modifying the state of the pinia store instead of calling $hydrate is that it would trigger "setItem" which would cause redundant overwriting of the storage and call "refresh-store" event in case of the previous example I provided. It would cause the infinite loop. I probably could make some if's and conditions but it's much uglier solution. Maybe I am missing something.

Additional context

There is npm package called "pinia-plugin-persistedstate" which has $hydrate method (you can find that in their documentation in "advanced usage" section) but since I need to use async storage, their plugin won't work for me.

stale[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.