prazdevs / pinia-plugin-persistedstate

💾 Configurable persistence and rehydration of Pinia stores.
https://prazdevs.github.io/pinia-plugin-persistedstate/
MIT License
2.15k stars 122 forks source link

[electron] Cannot persist #48

Closed hjw0968 closed 2 years ago

hjw0968 commented 2 years ago

electron V17 Vue3.2.29 vite2.8.6 typescript4.6.2 pinia2.0.11

image
prazdevs commented 2 years ago

Can you provide a proper repo to reproduce ?

hjw0968 commented 2 years ago
// /store/index.ts
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
// import piniaPersist from 'pinia-plugin-persist'
const store = createPinia()
store.use(piniaPluginPersistedstate)

export default store
// /store/user.ts
interface UserState {
    hasLogin: boolean
    isFirstOpen: boolean
    localhostIp: string
    userToken: string
    expirationLoginTime: number
    userInfo: User
}

export const useUserStore = defineStore({
    id: 'user',
    state: (): UserState => ({

        hasLogin: false,
        isFirstOpen: true, 

        localhostIp: "", 
        userToken: '',
        expirationLoginTime: 0,

        // @ts-ignore
        userInfo: {
            id: 0,
            username: 'xx',
            nickname: 'xx',
            motto: '',
            avatar: 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png'
        }
    }),
    getters: {
        getUserInfo: state => state.userInfo
    },
    actions: {
        userLoginInit(userInfo: User) {
            this.hasLogin = true
            this.userInfo = userInfo
        },
        resetUserToken(token: string) {
            // window.electron.Authorization = token
            localStorage.setItem('Authorization', token)
            this.userToken = token
            if (isNull(token)) {
                this.hasLogin = false
            }
        },
        resetExpLoginTime(expires_in: number) {
            this.expirationLoginTime = dayjs().add(expires_in, 's').unix()
        }
    },
    persist: {
        storage: localStorage,
        paths: [
            'hasLogin',
            'isFirstOpen',
            'localhostIp',
            'userToken',
            'expirationLoginTime',
            'userInfo',
        ],
        beforeRestore: context => {
            console.log('Before hydration...')
        },
        afterRestore: context => {
            console.log('After hydration...')
        },
    },
})
//package.json
  "dependencies": {
    "@electron/remote": "^2.0.7",
    "ant-design-vue": "^3.0.0-beta.13",
    "axios": "^0.26.1",
    "cnchar": "^3.0.3",
    "core-js": "^3.21.1",
    "dayjs": "^1.10.8",
    "dexie": "^3.2.1",
    "dotenv": "^8.2.0",
    "electron-json-storage": "^4.5.0",
    "js-base64": "^3.6.1",
    "nanoid": "^3.1.25",
    "pinia": "^2.0.11",
    "pinia-plugin-persist": "0.0.7",
    "pinia-plugin-persistedstate": "^1.5.1",
    "protobufjs": "^6.11.2",
    "vue": "^3.2.31",
    "vue-router": "^4.0.14",
    "vue3-lazy": "^1.0.0-alpha.1"
  },
  "devDependencies": {
    "@ant-design/icons-vue": "^6.0.1",
    "@types/chai": "^4.2.11",
    "@types/mocha": "^5.2.4",
    "@typescript-eslint/eslint-plugin": "^2.33.0",
    "@typescript-eslint/parser": "^2.33.0",
    "@vue/cli-plugin-babel": "^5.0.1",
    "@vue/cli-plugin-typescript": "^5.0.1",
    "@vue/cli-plugin-unit-mocha": "^5.0.1",
    "@vue/cli-service": "^5.0.1",
    "@vue/compiler-sfc": "^3.0.0",
    "@vue/eslint-config-typescript": "^5.0.2",
    "@vue/test-utils": "^2.0.0-rc.17",
    "babel-plugin-import": "^1.13.3",
    "chai": "^4.1.2",
    "electron": "^17.1.2",
    "electron-builder": "^22.14.13",
    "electron-devtools-installer": "^3.2.0",
    "electron-reloader": "^1.1.0",
    "less": "^4.1.2",
    "less-loader": "^10.2.0",
    "sass": "^1.49.9",
    "sass-loader": "^12.6.0",
    "typescript": "^4.6.2",
    "webpack": "^5.70.0"
  }

That's it

use https://github.com/Seb-L/pinia-plugin-persist 0.0.7 version, It uses watch(() => store.$state, () => {}), so there is no such problem. Now it also uses store$ Subscribe (1.0.0 version), like your library, has the same problem of non persist. It's really not clear what caused it

zhenyuWang commented 2 years ago

When I use version 0.0.93, it's fine. When I use version 1.0.0, I refresh the page and some data cache fails. I don't know why, but there is a problem.

prazdevs commented 2 years ago

Also, have you tried using pinia's very simple recommendation on subscribing to state where you can watch the state? https://pinia.vuejs.org/core-concepts/state.html#subscribing-to-the-state

watch(
  pinia.state,
  (state) => {
    // persist the whole state to the local storage whenever it changes
    localStorage.setItem('piniaState', JSON.stringify(state))
  },
  { deep: true }
)

this is far from the plugin, but can help to see where the problem is coming from

BkunS commented 2 years ago

I encountered the same issue by not seeing initial state saved to storage, which I believe should be the expected behavior. After playing around a little bit, I believe that initializing store does NOT trigger the store.$subscribe(), hence no way to save the initial state to storage.

My suggestion is to change here a little bit:

...
// src/index.ts line 114
    beforeRestore?.(context)

    try {
      const fromStorage = storage.getItem(key)
      if (fromStorage) {
          store.$patch(serializer.deserialize(fromStorage))
      } 
      // Save initial state if not having fromStorage values:
      else {
          storage.setItem(key, serializer.serialize(store.$state))
      }
    } catch (_error) {}

    afterRestore?.(context)
...
yfxie commented 2 years ago

@BkunS @hjw0968 Probably you guys passed a new pinia instance to the vue app. Check your app.use()

import { createApp } from "vue";
import { createPinia } from "pinia";
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
import App from "./App.vue";

const app = createApp(App);

const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);

app.use(pinia); // ✅ should pass the pinia instance which use the plugin
app.use(createPinia()); // ❌ shouldn't pass a new pinia instance
BkunS commented 2 years ago

No, just double-checked and this is not the case.

@BkunS @hjw0968 Probably you guys passed a new pinia instance to the vue app. Check your app.use()

import { createApp } from "vue";
import { createPinia } from "pinia";
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
import App from "./App.vue";

const app = createApp(App);

const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);

app.use(pinia); // ✅ should pass the pinia instance which use the plugin
app.use(createPinia()); // ❌ shouldn't pass a new pinia instance
kagaricyan commented 2 years ago

When I use version 0.0.93, it's fine. When I use version 1.0.0, I refresh the page and some data cache fails. I don't know why, but there is a problem.

Also, have you tried using pinia's very simple recommendation on subscribing to state where you can watch the state? https://pinia.vuejs.org/core-concepts/state.html#subscribing-to-the-state

watch(
  pinia.state,
  (state) => {
    // persist the whole state to the local storage whenever it changes
    localStorage.setItem('piniaState', JSON.stringify(state))
  },
  { deep: true }
)

this is far from the plugin, but can help to see where the problem is coming from

I also downgrade to 0.0.93, that's work fine.

prazdevs commented 2 years ago

Closing this issue as stale, and it doesnt include a proper reproduction repo. If the issue persists, feel free to reopen with a reproduction repo! :)

wordscode commented 7 months ago

electron V17 Vue3.2.29 vite2.8.6 typescript4.6.2 pinia2.0.11

image

鸡哥,2年了,pinia 还是不会持久化Set集合,怎么搞

import { defineStore } from 'pinia'
import { parse, stringify } from 'zipson'
import type { StateTree } from 'pinia'

export const useHomeStore = defineStore(
  'gp-home',
  () => {
    //pinia-plugin-persistedstate :基本类型之外的将不会被持久化
    const historySet = new Set<string>([])
    const addSet = (s: string) => {
      historySet.add(s)
    }

    return {
      historySet,
      addSet
    }
  },
  {
    persist: {
      serializer: {
        serialize: (state: StateTree): string => stringify(state),
        deserialize: (state: string): StateTree => parse(state)
      }
    }
  }
)

I use custom serializer but doesn't work , still could not save in local storage