pinia-plugin-persistedstate

repository·main·Indexed 25 days ago

https://github.com/prazdevs/pinia-plugin-persistedstate

A Pinia plugin providing configurable persistence and rehydration for stores, allowing state to survive page reloads. It supports custom storage engines, serializers, and state picking/omitting. Version 4.5.0 includes a dedicated SSR-friendly module for Nuxt with cookie storage support, as well as compatibility with other Vue frameworks like Quasar, Ionic, and Vike.

Tokens
7.5K
Snippets
29
Records
45
Agent score
81%

What's inside pinia-plugin-persistedstate

  1. Overview of pinia-plugin-persistedstate features

    main

    The plugin provides several capabilities for managing state persistence:

    • API Compatibility: Uses an API similar to vuex-persistedstate.
    • Granular Control: Supports per-store configuration and multiple configurations per store.
    • Extensibility: Allows for custom storage engines and custom data serializers.
    • Lifecycle Hooks: Provides pre/post persistence and hydration hooks.

    Note for Nuxt users: This package exports a dedicated module for better Nuxt integration and out-of-the-box SSR support. Refer to the Nuxt-specific documentation for setup.

  2. Understand persistence in Setup Stores

    main

    When using the setup store syntax (Composition API style), the following rules apply to what gets persisted:

    1. Only returned ref()s are persisted: Only ref()s that are explicitly returned from the setup function are treated as state and can be persisted.
    2. computed()s are never persisted: Regardless of whether they are returned or not, computed() properties are treated as getters and cannot be persisted.

    Note: You must return all state properties in setup stores for Pinia to recognize them as state in the first place.

  3. When to use pinia-plugin-persistedstate

    main

    Use pinia-plugin-persistedstate when you want a consistent API for persistence across your entire project. The plugin is designed for scenarios ranging from simple default persistence (saving the entire store) to complex requirements, such as:

    • Fine-grained configuration (selecting specific state properties to persist).
    • Using multiple different storages.
    • Implementing custom serializers.

    All these configurations are managed via a single persist option directly on the stores you wish to persist.

  4. Handle lost object references during persistence

    main

    Because the plugin uses a serialization process, object references are lost upon refresh. If two variables a and b point to the same object before serialization, they will become two distinct objects with identical content after deserialization (a === b will be false). This breaks reactivity between them.

    Workaround: To restore reactivity, you can:

    1. Use the pick option to exclude one of the references from being persisted.
    2. Use the afterHydrate hook to manually re-assign the reference (e.g., setting b = a) after the state has been rehydrated.
    // Example of the problem:
    const a = {
      1: 'one',
      2: 'two',
    }
    const b = a
    
    // Before serialization:
    a === b // -> true
    
    // After deserialization:
    a === b // -> false
  5. Compare pinia-plugin-persistedstate with manual persistence using VueUse

    main

    You do not strictly need a plugin to persist Pinia stores. You can achieve persistence manually by using utilities like VueUse's useLocalStorage inside your store definition. This approach is useful for simple use cases where you want to manage specific state properties directly with a storage utility without configuring a global Pinia plugin.

    import { useLocalStorage } from '@vueuse/core'
    import { defineStore } from 'pinia'
    
    defineStore('store', () => {
      const someState = useLocalStorage('stored-state', 'initialValue')
    
      return { someState }
    })
  6. Ensure custom storage methods are synchronous

    main

    When providing a custom storage configuration, all its methods must be synchronous. This is a requirement because Pinia's state subscription mechanism ($subscribe) is synchronous.

    If you need to use an asynchronous storage engine, a possible workaround is to subscribe to actions using Pinia's $onAction instead of relying on the plugin's automatic state subscription.

  7. Persist non-primitive types like Date

    main

    Non-primitive types (such as Date objects) are not rehydrated as their original types due to the serialization process; they are instead rehydrated as strings.

    Workarounds:

    • Use the afterHydrate hook to manually recreate the objects (e.g., converting the string back into a new Date()) after rehydration.
    • Implement a custom serializer that supports the specific data types you need to persist.
  8. Use pinia-plugin-persistedstate with other Vue frameworks

    main

    While official support is only provided for Nuxt, pinia-plugin-persistedstate can be used in most other Vue frameworks (such as Quasar, Ionic, or Vike) because it functions as a standard Pinia plugin.

    Note: When using the plugin in non-Nuxt frameworks, be mindful of potential Server-Side Rendering (SSR) caveats, as the plugin's behavior regarding state hydration and persistence may vary depending on the framework's implementation.

  9. Register pinia-plugin-persistedstate with Pinia

    main

    After installing, you must register the plugin with your Pinia instance using pinia.use().

    import { createPinia } from 'pinia'
    import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
    
    const pinia = createPinia()
    pinia.use(piniaPluginPersistedstate)
  10. Enable persistence in a Pinia store with Nuxt

    main

    Once the module is installed, you can enable persistence by setting the persist option to true in your store definition. This works with both the setup syntax and the option syntax.

    import { defineStore } from 'pinia'
    import { ref } from 'vue'
    
    export const useStore = defineStore(
      'main',
      () => {
        const someState = ref('hello pinia')
        return { someState }
      },
      {
        persist: true,
      },
    )