nuxt3+pinia环境下实现数据持久化
在我写nuxt3项目时,遇到了使用pinia在页面刷新时数据丢失的老生常谈的问题,在这里简单记录下我的解决方案文章主要介绍了两种使用vueuse的useStorage使用pinia的插件。
前言
在我写nuxt3
项目时,遇到了使用pinia
在页面刷新时数据丢失的老生常谈的问题,在这里简单记录下我的解决方案
工程搭建
这里我就不做过多的工程搭建介绍,我是跟着nuxt官网步骤完成的工程初始化,完整的工程代码可点击链接查阅
初始化后的工程结构如下
配置并使用pinia
根据pinia官网的步骤配置即可
首先安装相关依赖
pnpm add pinia @pinia/nuxt
复制代码
然后进行配置,修改nuxt.config.ts
export default defineNuxtConfig({
+ modules: [
+ '@pinia/nuxt'
+ ]
})
复制代码
个人习惯,我会配置一个autoImport,运行时自动引入defineStore
export default defineNuxtConfig({
modules: [
'@pinia/nuxt'
],
+ pinia: {
+ autoImports: [
+ 'defineStore', // import { defineStore } from 'pinia'
+ ],
+ }
})
复制代码
新建目录composables
,新建文件store.ts
export const useNuxtStore = defineStore('nuxtStore', () => {
const state = ref(0)
const setState = (num: number) => {
state.value = num
}
return {
state,
setState,
}
})
复制代码
我这里的写法是Setup Stores,就像是一个普通的composable
,只不过使用defineStore
定义生成
定义好store
之后,我们在app.vue
中使用store
<script setup lang="ts">
const store = useStateStore()
</script>
<template>
<div style="font-size: 40px; line-height: 60px;">
<div>Hi! I'm nuxt project!</div>
<div>
Here state: {{ store.state }}
<button @click="store.setState">setState</button>
</div>
</div>
</template>
复制代码
这时候保存即可看到效果
提个醒,我这里直接使用的const store = useStateStore()
而没有解构,是因为解构后会丢失响应式,如果你需要解构直接使用state
并且保持响应式,可以使用storeToRefs
多次点击setState
按钮会增加state
的数值,当页面刷新之后,state
会变回0
到这里工程就算是搭建好了,下面来讲解持久化保持数据的处理方法
使用vueuse
vueuse
中有个storage
相关的hook,我们可以使用hook来手动保存store
,在刷新的时候会从storage
中读取,就能达到数据保存的效果
我们需要配置nuxt+vueuse
的环境,这里根据vueuse官网进行配置即可
首先安装依赖
pnpm add @vueuse/nuxt @vueuse/core
复制代码
然后配置nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@pinia/nuxt',
+ '@vueuse/nuxt',
],
pinia: {
autoImports: [
'defineStore', // import { defineStore } from 'pinia'
],
}
})
复制代码
这样就能直接在工程中使用@vueuse/core
的所有hook了
我们使用useSessionStorage
hook来进行缓存,修改composables/store.ts
export const useStateStore = defineStore('nuxtStore', () => {
- const state = ref(0)
+ const state = useSessionStorage('nuxt-store-test', 0)
const setState = () => {
state.value = state.value + 1
}
return {
state,
setState,
}
})
复制代码
这里我们使用useSessionStorage
来初始化state
,在应用首次运行的时候,session-storage
中不存在nuxt-store-test
这个键值对,所以就取第二个默认值参数作为初始值
保存运行后可以看到,控制台中多了个nuxt-store-test
键值对
当我点击按钮改变state
的时候,控制台中nuxt-store-test
的值也跟着改变
当页面刷新的时候,期望场景是state
的值会保持不变,但其实发现,state
会变回0
具体原因在pinia文档里也有讲解,在SSR环境下使用部分composables
需要额外注意
当我们在SSR下使用useSessionStorage
时,需要考虑hydrate
阶段的处理,state
的值应该从浏览器读取,而不需要在hydrate
阶段进行激活,所以我们需要对这些字段跳过处理
我们修改composables/store.ts
+ import { skipHydrate } from 'pinia'
export const useStateStore = defineStore('nuxtStore', () => {
const state = useSessionStorage('nuxt-store-test', 0)
const setState = () => {
state.value = state.value + 1
}
return {
+ state: skipHydrate(state),
setState,
}
})
复制代码
使用skipHydrate
方法,标记state
属性不能被激活,需要到浏览器中读取数值,这样处理后在页面刷新时也能保持数据的内容
使用pinia插件实现持久化
这应该是比较普遍的做法,像vuex时期也是用持久化插件来实现
在pinia
中有个下载量较多的插件pinia-plugin-persistedstate
,这是插件文档
首先安装插件
pnpm add @pinia-plugin-persistedstate/nuxt
复制代码
然后配置nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@pinia/nuxt',
'@vueuse/nuxt',
+ '@pinia-plugin-persistedstate/nuxt',
],
pinia: {
autoImports: [
'defineStore', // import { defineStore } from 'pinia'
],
},
+ piniaPersistedstate: {
+ storage: 'sessionStorage',
+ }
})
复制代码
新建文件composables/plugin.ts
,在这里写使用插件的store
export const usePluginStateStore = defineStore('pluginStore', () => {
const pState = ref(0)
const setPState = () => {
pState.value += 1
}
return {
pState,
setPState,
}
}, {
persist: true,
})
复制代码
重点是,在defineStore
方法的第三个参数,要传入persist: true
,表示这个store要进行持久化处理
在app.vue
中使用该store
<script setup lang="ts">
const store = useStateStore()
+ const pStore = usePluginStateStore()
</script>
<template>
<div style="font-size: 40px; line-height: 60px;">
<div>Hi! I'm nuxt project!</div>
<div>
Here state: {{ store.state }}
<button @click="store.setState">setState</button>
</div>
+ <div>
+ Here plugin state: {{ pStore.pState }}
+ <button @click="pStore.setPState">setPState</button>
+ </div>
</div>
</template>
复制代码
这时候点击setPState
按钮,控制台就会保存pState
的值,并且刷新后也能展示
使用其他pinia插件
以上两种方案已经能很好的解决现有问题,但如果你还希望使用其他pinia
插件,而该插件没有做nuxt
版本呢
在pinia文档中有介绍在nuxt
环境下如何使用pinia
插件,按照如下方式使用即可,这里没有进行验证,想用这种方式的需要自行验证使用
// plugins/myPiniaPlugin.ts
import { PiniaPluginContext } from 'pinia'
function MyPiniaPlugin({ store }: PiniaPluginContext) {
store.$subscribe((mutation) => {
// react to store changes
console.log(`[🍍 ${mutation.storeId}]: ${mutation.type}.`)
})
// Note this has to be typed if you are using TS
return { creationTime: new Date() }
}
export default defineNuxtPlugin(({ $pinia }) => {
$pinia.use(MyPiniaPlugin)
})
复制代码
总结
文章主要介绍了两种nuxt3+pinia
的数据持久化处理:
- 使用
vueuse
的useStorage
/useLocalStorage
/useSessionStorage
- 使用
pinia
的插件pinia-plugin-persistedstate
更多推荐
所有评论(0)