Code Monkey home page Code Monkey logo

pinia-plugin-persist's Introduction

pinia-plugin-persist

Build Docs

Persist VueJs Pinia state data in sessionStorage or other storages, heavilly influenced by vuex-persistedstate.

Documentation: HERE

pinia-plugin-persist's People

Contributors

seb-l avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

pinia-plugin-persist's Issues

Is $patch had no effect?

app.js
`import { defineStore } from 'pinia'
import { ref, reactive } from 'vue'

export const useAppStore = defineStore('app', () => {
// state
const isCollapse = ref(false)

// actions
function setIsCollapse(isCollapse) {
this.isCollapse = isCollapse
}

return {
isCollapse
setIsCollapse
}
}, {
persist: {
enabled: true,
strategies: [
{
key: 'appStore',
storage: localStorage
},
]
}
})
`
isCollapse default value is false,in the page ,I clicked a button change value to true
In localStorage ,have object
{
isCollapse: true
}

then I refresh this page , isCollapse 's value should be true

but actually , the value is false

so I think is $patch had no effect?

image

The custom storage is inited during define instead of use, which is imcompitible with hooks.

The custom storage is a Object parameter of pinia-plugin-persist

// this will blow up in nuxt SSR because it is not in a component.
const token = useCookie<string>('userToken', rawEncode)
const cookiesStorage = {
  setItem (_key: string, state: string) {
    try {
      token.value = JSON.parse(state).userToken
    } catch (err) {
      return undefined
    }
  },
  getItem (_key: string) {
    try {
      return JSON.stringify({ userToken: token.value })
    } catch (err) {
      return undefined
    }
  }
}
const useStore = defineStore({
  // ...
  persist: {
    enabled: true,
    strategies: [
      {
        storage: cookiesStorage,
        paths: ['accessToken']
      },
    ],
  }
}

It runs before the useStore.

But this is problematic when using with SSR frameworks.

Because SSR frameworks (such as nuxt) relies on useSSRContext to retrieve of information about current request.
Which isn't available outside of component life cycle.

My current hack about this is

const useStore = defineStore({
  // ...
    strategies: [
      {
        get storage () { return getCookiesStorage() as unknown as Storage },
        paths: ['userToken']
      }
    ]
  // ...
})

To delay the deference of getCookiesStorage and prevent it from crash the server.
But that isn't a proper usage at all.

I think this should be changed to (or as an alternative option) a factory function that called during useStore, so it don't cause probelm.

Persistence doesn't work well when using multiple pinia stores.

It works totally fine when there was only ONE pinia store in my application. After I added another pinia definition and it just went weird. It seems that there could be ONLY ONE store that can be persisted into the storage at a time, while others just freeze in the storage, no matter when any actions or $reset being called.
And pinia works fine, though. Just the persistence goes wrong.

// authStore.js
const useAuthStore = defineStore("auth", { ... })

// routerStore.js
const useRouterStore = defineStore("router", { ... })

Here are the dependencies in my package.json:

"dependencies": {
   // ......
    "pinia": "^2.0.0-rc.10",
    "pinia-plugin-persist": "^1.0.0",
    "vue": "^3.2.25",
  }

Plugin not working with Nuxt 2

Hey there,

I followed the integration instructions in the documentation and am receiving an error.

I've created a reproduction here: https://github.com/hex-digital/nuxt-2/tree/pinia-persist and a PR to see it more easily here (hex-digital/nuxt-2#1)

It's set up by:

  • Install Nuxt via yarn create nuxt-app fresh-nuxt
  • Add deps via yarn add -D pinia @pinia/nuxt @nuxtjs/composition-api pinia-plugin-persist
  • Add entries to buildModules as per this plugins docs
buildModules: [
  '@nuxtjs/composition-api/module',
  '@pinia/nuxt',
  'pinia-plugin-persist/nuxt',
];

Steps to reproduce

  • Run yarn dev
  • Observe error in terminal:
❯ yarn dev
yarn run v1.22.17
$ nuxt

 FATAL  Package subpath './nuxt' is not defined by "exports" in /Users/jamie/Sites/bignight/fresh-nuxt/node_modules/pinia-plugin-persist/package.json

  at new NodeError (node:internal/errors:371:5)
  at throwExportsNotFound (node:internal/modules/esm/resolve:440:9)
  at packageExportsResolve (node:internal/modules/esm/resolve:692:3)
  at resolveExports (node:internal/modules/cjs/loader:482:36)
  at Function.Module._findPath (node:internal/modules/cjs/loader:522:31)
  at Function.Module._resolveFilename (node:internal/modules/cjs/loader:919:27)
  at Function.resolve (node:internal/modules/cjs/helpers:108:19)
  at p (node_modules/jiti/dist/jiti.js:1:52925)
  at Resolver.g [as _require] (node_modules/jiti/dist/jiti.js:1:54200)
  at Resolver.requireModule (node_modules/@nuxt/core/dist/core.js:381:29)


   ╭────────────────────────────────────────────────────────────────────────────────────────────────────╮
   │                                                                                                    │
  1 export default {
   │   ✖ Nuxt Fatal Error                                                                               │
   │                                                                                                    │
   │   Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './nuxt' is not defined by "exports" in   │
   │   /Users/jamie/Sites/bignight/fresh-nuxt/node_modules/pinia-plugin-persist/package.json            │
   │                                                                                                    │
   ╰────────────────────────────────────────────────────────────────────────────────────────────────────╯

error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

image

Other Notes

Note that for Nuxt, the Pinia docs say to add @pinia/nuxt to buildModules, but this plugins docs say to add pinia/nuxt. Adding pinia/nuxt as you suggest gives a similar error relating to pinia.

Incompatibility with new Pinia version

Minimal repro

Steps to reproduce:

  1. npm i
  2. npm run build
  3. Error is shown

Expected behavior:

Successful build.

Actual behavior:

The following error is shown:

node_modules/pinia-plugin-persist/dist/index.d.ts:1:21 - error TS2724: '"pinia"' has no exported member named 'GettersTree'. Did you mean '_GettersTree'?

1 import { StateTree, GettersTree, PiniaPluginContext } from 'pinia';

Error as image

Thank you for the plugin!

TypeScript5.0+ moduleResolution bundler breaks types import

I created a new vue-ts project using pnpm create vite@latest my-app --template vue-ts, then I add pinia & pinia-plugin-persist deps。I set up typescript config by the doc, when i import pinia-plugin-persist, vscode will raise an error:

Could not find a delaration file for module pinia-plugin-persist.
There are types at '/xxx/my-app/node_modules/.pnpm/pinia-plugin-persist/dist/index.d.ts', but this result could not be resolved when respectiong package.json "exports". The 'pinia-plugin-persist' library may need to update its package.json or typings.

Here is my tsconfig.json file:

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,

    "types": ["pinia-plugin-persist"]
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

To fix this bug, I have to change the config:

--     "moduleResolution": "bundler",
++    "moduleResolution": "node",

Please support typescript 5.0+!

May be this link clarifies the problem more clean: Add the types condition to the package.json#exports

A weird bug that loses data when I refresh the page

  1. On the home page, click the login out button to log out
  2. On the login page, enter your email address and name to enter the home page
  3. Click Refresh (F5) to refresh the interface, user information will be lost (upper right corner)

tip:
However, directly enter the login (http://localhost:3000/login), enter the email address and name, click login, and
enter the home page. At this time, clicking refresh will not lose user information.

you can find code in the here pinia-plugin-persist-bug-recurrent

replay.mp4

Storage not found when using in nuxt environment

There is no problem when using the Basic Usage method.
When using separate storage(localStorage, sessionStorage) for strategies in Advanced Usage
I get an 'is not defined' error.
Do I need any special settings?

Async storage provider

Is there any intent to be able to support an async storage provider like localforage?

import localforage from 'localforage'

export default {
    setItem: async (key, value) => {
      return localforage.setItem(key, value)
    },
    getItem: async (key) => {
      return localforage.getItem(key)
    }
}

I did try the above without any success.

How to implement in Nuxt 3?

Hi,

How can this plugin be implemented in a Nuxt 3 project? and also what would be the way to use local Storage and cookies, or just localStorage?
Would it be possible to add this to the documentation?

Thanks

Nuxt 2 TS error

I'm using Vue 2.7 + Nuxt 2.16 + @nuxtjs/composition API

export const useDictionaryStore = defineStore(
  'dictionary',
  () => {
    // ...code removed

    return {
       someData,
    }
  },
  {
    persist: {
      enabled: true,
      strategies: [
        {
          storage: localStorage,
        },
      ],
    },
  }
)

Getting TS error: Argument of type '{ persist: { enabled: boolean; strategies: { storage: Storage; }[]; }; }' is not assignable to parameter of type 'DefineSetupStoreOptions<"dictionary", _UnwrapAll

Even though i've added types in tsconfig.json

How to persist state if the default state has not changed?

How do I persist the state of a store if the initial default state has not changed? If the defaults are accepted, I don't need to ask for the user's preferences for another 365 days. But I must get the user to accept the defaults before using them.

I am creating a store that starts with everything given a default value. If a user changes any default values, it saves the store to a cookie. However, if the user accepts the default values without changing anything and presses an 'agree' button, the store’s state does not get saved into a cookie. No cookie is created.

I looked at the source and found updateStorage and wondered if that could be used in my component’s agree method. However, updateStorage expects a strategy as its first argument, but I don’t necessarily know the strategy inside a component, and a store could have more than one.

How to use with Vue 3

The docs have instruction for how to use this plugin with Vue 2 and Nuxt but nothing for Vue 3.

Thanks for writing this plugin.

vue3 watch引用引入不对

import { watch } from '@vue/composition-api';
change to:
import { watch } from '@vue/runtime-core';
runtime no error
but not work

当组件被卸载时subscriptions将被自动删除

默认情况下,state subscriptions 绑定到添加它们的组件(如果 store 位于组件的 setup() 中)。 意思是,当组件被卸载时,它们将被自动删除。 如果要在卸载组件后保留它们,请将 { detached: true } 作为第二个参数传递给 detach 当前组件的 state subscription

see here

store.$subscribe(() => {
      strategies.forEach((strategy) => {
        updateStorage(strategy, store);
      });
},{ detached: true });

export { index as default, updateStorage }

vue3 ssr
add "pinia-plugin-persist"
npm run build

run worry

/src/node_modules/pinia-plugin-persist/dist/pinia-persist.es.js:38
export { index as default, updateStorage };
^^^^^^

SyntaxError: Unexpected token 'export'
at internalCompileFunction (node:internal/vm:73:18)
at wrapSafe (node:internal/modules/cjs/loader:1178:20)
at Module._compile (node:internal/modules/cjs/loader:1220:27)
at Module._extensions..js (node:internal/modules/cjs/loader:1310:10)
at Module.load (node:internal/modules/cjs/loader:1119:32)
at Module._load (node:internal/modules/cjs/loader:960:12)
at ModuleWrap. (node:internal/modules/esm/translators:169:29)
at ModuleJob.run (node:internal/modules/esm/module_job:194:25)

package.json
add type=module

Multiple Pinia stores seems to break persistence

I'm currently working on getting a minimum reproducible example for this problem but long story short it seems to be that if:

  • You have multiple stores (as expected with pinia)
  • You have 1 persistent configuration using localstorage
  • You have 1 other persistent configuration using sessionstorage
  • Possibly: at least one store called outside of a hook and provided with the pinia instance as per the docs

Only 1 type of storage will be initialised and only one store will have it's data available there.

Will update the issue with more info and possibly a PR as I go.

When persisted into an array, the underlined fields will be changed to camel case.

environment

  • vue3: 3.2.22
  • pina: 2.0.14

Problem statement
When using pina persistence, if an array is stored and the field in the array object is underlined, the plug-in will change it to camel case.

  1. my code
import { defineStore } from "pinia"

export const useItemStore = defineStore({
    id: 'useItemStore',
    state: () => {
        return {
            rowItem: {
               
            }
        }
    },
    getters: {
        getCurItem(state) {
            return state.rowItem
        }
    },
    actions: {
        setMenuItem(val: any) {
            this.rowItem = val
        },
        resetData() {
            this.rowItem = {}
        }
    },
    persist: {
        enabled: true,
        strategies: [
            {
                key: 'useItemStore',
                storage: sessionStorage
            }
        ]
    }
})


const data = [
    {
        "id": "653773c022bd673a6b02dd88",
        "admin_id": "JSZH00005",
        "name": "root",
        "email": "[email protected]",
        "phone": "13800000000",
        "role_id": "6537739b339a3a4728017968",
        "role_name": "amin",
        "status": 1,
        "node_id": null,
        "created_at": "2023-10-24 07:35:29",
        "updated_at": "2024-04-10 11:40:16"
    },
    {
        "id": "64b89e21050ca676f20c191b",
        "admin_id": "JSZH00004",
        "name": "dev",
        "email": "[email protected]",
        "phone": "15088888888",
        "role_id": "64b89defd7098d53b00a18f6",
        "role_name": "dev",
        "status": 1,
        "node_id": "123",
        "created_at": "2023-07-20 02:38:25",
        "updated_at": "2024-04-10 11:08:05"
    },
    {
        "id": "64b0bac0e966e166d9093d23",
        "admin_id": "JSZH00001",
        "name": "admin",
        "email": "[email protected]",
        "phone": "18688889999",
        "role_id": "64b0bac0e966e166d9093d22",
        "role_name": "superadmin",
        "status": 1,
        "node_id": "Ziz78vM5cAxBayywmAMnXFpLWe21UpeA5i",
        "created_at": "2023-07-14 03:02:24",
        "updated_at": "2024-04-10 11:53:19"
    }
]
//use
itemStore.setMenuItem(data)

2.The last underscored field in the array will not be changed to camelCase, and the other fields will be created with CamelCase.
image

image

It can be seen that as long as it is not the last item in the array, underlined camel case data will be created.

for second time without refreshing page it dosent store the data

So i am having an issue when user login store is set with user data and all for first time it store it in localstorage or sessionstorage, when the user logouts the storage clear function will be called. after if i try to login with out refreshing the page presist doesn't work.
***note even when login in the second time pinia get populated with data

trap returned falsish for property

Thank you for a great plugin.

May I suggest to adapt the docs according to a bug I had last night?

I write my vues, including the pinia stores along the script setup syntax

So, I was struggling a few hours on a

'set' on proxy: trap returned falsish for property bug

The property that lifted the error was a getter (computed, read-only).

Using

{
    persist: {
        enabled: true
    }
}

will persist all the variables, including the getters.

Navigating from page to page or refreshing a page will try to set a getter though a getter is read-only.

Solution:

you must use strategies and restrict the variables that are persisted with path (and avoid having a getter in the path)

{
    persist: {
        enabled: true,
        strategies: {
            path: ['state_variable_1', 'state_variable_2', '...] // avoid getter in the list
         }
     }
}

Proposal to Add Cross-Page State Synchronization to Pinia Plugin Persist

It is suggested to add a new feature to enable cross-page state synchronization in Pinia Plugin Persist. This feature can work with listening to the localStorage event, which will automatically synchronize the status of other web pages after one page updates the status. This will make it easier to handle most complex synchronization logic.

useEventListener(window, 'storage', (event) => {
    if (event.key === STORAGE_KEY) {
      const obj = JSON.parse(event.newValue || '{}')
      mykey.value = obj.mykey
    }
})

在pinia中默认组件卸载后订阅的更新函数会被删除

默认情况下,state subscriptions 绑定到添加它们的组件(如果 store 位于组件的 setup() 中)。 意思是,当组件被卸载时,它们将被自动删除。 如果要在卸载组件后保留它们,请将 { detached: true } 作为第二个参数传递给 detach 当前组件的 state subscription

see here

store.$subscribe(() => {
      strategies.forEach((strategy) => {
        updateStorage(strategy, store);
      });
},{ detached: true });

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.