Closed AndreiSoroka closed 2 years ago
Hi, I think this is out of the scope of the package, but I can give you a solution for this.
You can decalre your store state using setup function and the createGlobalState
or createSharedComposable
from VueUse, I think it fits perfectly what you're looking for!
https://vueuse.org/shared/createglobalstate/
@prazdevs thanks for your answer.
Maybe is it possible add setup
? like this code:
import { defineStore } from 'pinia'
export const useStore = defineStore('main', {
state: () => {
return {
someState: 'hello pinia',
nested: {
data: 'nested pinia',
},
}
},
persist: {
key: 'storekey',
setup(context, presisData) {
// ... here I can add listeners when tab is opened
},
storage: window.sessionStorage,
paths: ['nested.data'],
beforeRestore: (context) => {
console.log('Before hydration...')
},
afterRestore: (context) => {
console.log('After hydration...')
},
},
})
How does it help me? I can add listeners when the tab is opened like this
document.addEventListener('visibilitychange', () => { // when tab is active then need restore from other tab
if (document.hidden) {
return;
}
storeAuth.$state = storage.genericStore(
storeAuth.$state,
isAuthState,
{ isLoading: false },
);
});
P.s. My temporary resolve:
Storage class (only for function genericStore)
class Storage {
#name = '';
constructor(name: string) {
this.#name = name;
}
getPersistedState() {
try {
const data = localStorage.getItem(this.#name);
if (!data) {
return null;
}
return JSON.parse(data);
} catch (_) {
return null;
}
}
setPersistedState(data: object) {
try {
localStorage.setItem(this.#name, JSON.stringify(data));
} catch (e) {
console.log(e);
}
}
genericStore<Store>(
store: Store,
validator: (arg: unknown) => arg is Store,
forceData: Partial<Store> = {},
): Store {
const persistedState = this.getPersistedState();
return {
...store,
...(persistedState && validator(persistedState) ? persistedState : {}),
...forceData,
};
}
}
in pinia store:
// ...
// connect storage
const storage = new Storage('store-auth');
const useStoreAuth = defineStore('auth', {
state: (): AuthState => storage.genericStore<AuthState>( // get data from localstorage or use default (with types)
{
token: null,
tokenExpiration: null,
refresh: null,
refreshExpiration: null,
errorMessage: '',
isLoading: false,
tokenData: null,
},
isAuthState,
{
isLoading: false, // just reset part of state
},
)
/// .....
});
const storeAuth = useStoreAuth();
storeAuth.$subscribe((mutation, state) => { // save each mutation
if (mutation.type === 'patch object') {
storage.setPersistedState(state);
}
});
document.addEventListener('visibilitychange', () => { // when tab is active then need restore from other tab
if (document.hidden) {
return;
}
storeAuth.$state = storage.genericStore(
storeAuth.$state,
isAuthState,
{ isLoading: false },
);
});
export default useStoreAuth;
@AndreiSoroka you have this plugin for pinia to make the sync between tabs. I don't know if we can use it with persistentstate plugin : https://github.com/wobsoriano/pinia-shared-state
You can use afterRestore
as the setup hook
pinia-shared-state works, put this to plugins/1-pinia-shared-state.ts
:
import { PiniaSharedState } from "pinia-shared-state"
export default defineNuxtPlugin(() => {
const pinia = useNuxtApp().$pinia
pinia.use(PiniaSharedState({}))
})
@AndreiSoroka you have this plugin for pinia to make the sync between tabs. I don't know if we can use it with persistentstate plugin : https://github.com/wobsoriano/pinia-shared-state
I use https://vueuse.org/core/useStorage/ where no need to use MF (Module Federation). With MF https://github.com/vueuse/vueuse/issues/2916#issuecomment-1489032756
What do you think about will add a functional sync multi-tab? like this https://www.npmjs.com/package/vuex-multi-tab-state