8

I'm using Pinia for state managment, and I want the state to persist when the page is refeshed.

I'm aware of two options:

  1. Use a plugin. Vuex has a vuex-persistedstate plugin for this, and Pinia has a similar plugin but it's still under development.

  2. Use local storage. Luckily Quasar has a LocalStorage plugin which would be nice to use here. But I'm not sure how to integrate it with Pinia, thus the reason for this post.

I found a nice tutorial doing something similar with Pinia + Vueuse.

And I tried adapting it to my needs with Pinia + TypeScript + Quasar LocalStorage Plugin as per below:

import { User } from 'firebase/auth';
import { defineStore } from 'pinia';
import { LocalStorage } from 'quasar';

type CreateMutable<T> = { -readonly [P in keyof T]: CreateMutable<T[P]> };

export const useUserStore = defineStore('user', {
  state: () => ({
    // user: {} as CreateMutable<User>, // This was my previous non-persistent state
    user: LocalStorage.set('user', {}) as unknown as CreateMutable<User>, // This is my attempt at using LocalStorage persistent state
  }),
  actions: {
    setUser(userData: User) {
      this.user = userData;
    },
    setPhotoURL(photoURLData: string | null) {
      this.user.photoURL = photoURLData;
    },
  },
});

Unfortunately it doesn't work.

The state does not persist on page refresh.

Any ideas on how to make this work?

TinyTiger
  • 1,801
  • 7
  • 47
  • 92

3 Answers3

7

To initialize the user state with Local Storage data, use Quasar's LocalStorage.getItem(), and default to an empty object:

export const useUserStore = defineStore('user', {
  state: () => ({
    user: (LocalStorage.getItem('user') || {}) as CreateMutable<User>,
  }),
  ⋮

In the setUser action, call LocalStorage.set() to save the user data to Local Storage.

Since user is an object, clone the object instead of directly assigning it, so that the store does not unnecessarily retain a reference to external objects. If userData has nested properties, you can use Quasar's extend to deep-copy the object:

import { extend, LocalStorage } from 'quasar'

export const useUserStore = defineStore('user', {
  ⋮
  actions: {
    setUser(userData: User) {
      const copyOfData = { ...userData }
      // or...
      const copyOfData = extend(true /* deep */, {}, userData)

      LocalStorage.set('user', copyOfData)
      this.user = copyOfData
    },
  }
})

demo

tony19
  • 125,647
  • 18
  • 229
  • 307
2

I actually use "vanilla localStorage" and had no issues with that. I am not a big fan of to much libraries, for simple tasks (although for not using them for complicated tasks). Whatever, I am a fan of VueUse, too. This function I have not used, but I could imagine.it makes things even easier.

Vanilla localStorage

Set into local storage

localStorage.setItem("myStorageKey", "My persisted values");

Get from local storage

localStorage.getItem("myStorageKey");

State Mutation

Apart from that, I have not tried to set the localStoreage direct into the state. That seems like a red flag to me, as you usually should not directly mutate a state. But I am not sure in this case. I usually prepopulate the state which hard coded data (or just empty) and then I would write an action, which sets the data into the state.

Ehrlich_Bachman
  • 772
  • 1
  • 10
  • 23
2

There's quasar-v2-ssr-pinia repository created before Pinia has official Quasar support. I tried to add pinia-plugin-persist and pinia-plugin-persistedstate in this PR but these Pinia plugins didnt work with Quasar SSR, so Toby pushed an examples of persisted state using Quasar' Cookies, SessionStorage and LocalStorage adopters.

Good news: it's working and you can use any of storage adopters for any store.

Bad news: there's no partial store persistent but only whole store. We can create separate store to persist all its content as a workaround.

I'm planning to publish Toby's code to NPM to install it instead of copying from examples.