Reputation: 1652
Setup: I'm using Nuxt3 + Pinia + VueUse.
Goal:
I want to save a state of a pinia store to localstorage via VueUse: useStorage
.
Problem:
For some reason no item is created in localstorage. I feel like I'm missing something here. In components I can use useStorage
fine.
in stores/piniaStoreVueUse.js
import { defineStore } from 'pinia'
import { useStorage } from '@vueuse/core'
export const usePiniaStoreVueUse = defineStore('piniaStoreUseVue', {
state: () => {
return {
state: useStorage('my-state', 'empty'),
}
},
actions: {
enrollState() {
this.state = 'enroll';
},
emptyState() {
this.state = 'empty';
},
},
getters: {
}
});
in components/SampleComponentStatePiniaVueUse.vue
<script lang="ts" setup>
import { usePiniaStoreVueUse } from '~/stores/piniaStoreVueUse';
const piniaStoreVueUse = usePiniaStoreVueUse();
</script>
<template>
<div>
piniaStoreVueUse.state: {{ piniaStoreVueUse.state }}<br>
<button class="button" @click="piniaStoreVueUse.enrollState()">
enrollState
</button>
<button class="button" @click="piniaStoreVueUse.emptyState()">
clearState
</button>
</div>
</template>
<style scoped>
</style>
Thank you.
Upvotes: 9
Views: 17060
Reputation: 151
I found a solution to this problem and it seems to work pretty well. I have not done extensive testing but it seems to work.
After loads of digging I came across a page in the Pinia documentation: Dealing with Composables
NOTES:
npm i -D @vueuse/nuxt @vueuse/core
My Tested Code:
//storageTestStore.js
import { defineStore, skipHydrate } from "pinia";
import { useLocalStorage } from '@vueuse/core'
export const useStorageTestStore = defineStore('storageTest', {
state: () => ({
user: useLocalStorage('pinia/auth/login', 'bob'),
}),
actions: {
setUser(user) {
this.user = user
}
},
hydrate(state, initialState) {
// in this case we can completely ignore the initial state since we
// want to read the value from the browser
state.user = useLocalStorage('pinia/auth/login', 'bob')
},
})
test.vue (~~/pages/test.vue)
<script setup>
import { ref, onMounted } from "vue";
import { useStorageTestStore } from "~~/stores/storageTestStore";
const storageTestStore = useStorageTestStore();
// create array with 10 random first names
const firstNames = [
"James",
"John",
"Robert",
"Michael",
"William",
"David",
"Richard",
"Charles",
"Joseph",
"Thomas",
];
const updateUser = () => {
storageTestStore.setUser(
firstNames[Math.floor(Math.random() * firstNames.length)]
);
};
</script>
<template>
<div class="max-w-[1152px] mx-auto">
<h1 class="text-xl">{{ storageTestStore.user }}</h1>
<button
class="text-lg bg-emerald-300 text-emerald-900 p-5 rounded-lg"
@click="updateUser()"
>
Change User
</button>
</div>
</template>
<style scoped></style>
The state fully persisted after browser reloads and navigating in the application.
Upvotes: 12
Reputation: 51
I'm folowed this topic two week. My resoleved use plugin pinia-plugin-persistedstate. I'm touch plugin/persistedstate.js and add persist: true
, in Pinia defineStore()
First install plugin yarn add pinia-plugin-persistedstate
or npm i pinia-plugin-persistedstate
#plugin/persistedstate.js
import { createNuxtPersistedState } from 'pinia-plugin-persistedstate'
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.$pinia.use(createNuxtPersistedState(useCookie))
})
and
#story.js
export const useMainStore = defineStore('mainStore', {
state: () => {
return {
todos: useStorage('todos', []),
...
}
},
persist: true, #add this
getters: {...},
actions: {...}
})
Upvotes: 5
Reputation: 1652
Nuxt3 uses SSR by default. But since useStorage() (from VueUse) uses the browsers localstorage this can’t work.
Solution 1:
Disables SSR in your nuxt.config.js
export default defineNuxtConfig({
ssr: false,
// ... other options
})
Careful:
This globally disables SSR.
Solution 2:
Wrap your component in <client-only placeholder="Loading…”>
<client-only placeholder="Loading...">
<MyComponent class="component-block"/>
</client-only>
I'd love to hear about other ways to deal with this. I feel like there should be a better way.
Upvotes: 8
Reputation: 1
you can use ref with useStorage()
import { defineStore } from 'pinia'
import { useStorage } from '@vueuse/core'
export const usePiniaStoreVueUse = defineStore('piniaStoreUseVue', {
state: () => {
return {
state: ref(useStorage('my-state', 'empty')),
}
},
actions: {
enrollState() {
this.state = 'enroll';
},
emptyState() {
this.state = 'empty';
},
},
getters: {
}
});
Upvotes: -2