Vue3 Composition API页面重载后无法获取Pinia数据的问题
Vue3 + Pinia:页面重载/导航返回后Setup中数据丢失的问题
问题描述
使用Vue3 Composition API时,遇到页面重载或导航离开再返回后,Setup中通过ref()获取的Pinia store数据无法显示,但模板中直接调用store getter的部分正常。应用初始加载时两者都能正确显示,开发者工具显示store数据完整可用。
组件代码:
<script setup> import { ref } from 'vue' import { useProfileStore } from '@/stores/profile' const store = useProfileStore() import { useRoute } from 'vue-router' const route = useRoute() const profile = ref() profile.value = store.getProfileBySlug(route.params.slug) </script> <template> <div class="record"> <ul> <li><h2>Template</h2><p>{{ store.getProfileBySlug(route.params.slug) }}</p></li> <li><h2>Setup</h2><p>{{ profile }}</p></li> </ul> </div> </template>
Pinia Store代码:
import { defineStore } from 'pinia' export const useProfileStore = defineStore('profile_store', { state: () => ({ profiles: [], // ... }), getters: { profilesSorted: (state) => { // ... 排序逻辑 }, getProfileBySlug: (state) => { return (slug) => state.profiles.find((profile) => profile.slug === slug) }, }, actions: { async initData() { // ... 异步数据获取及转换逻辑,最终将结果赋值给this.profiles }, } })
原因分析
问题出在Setup中的一次性赋值:
profile.value = store.getProfileBySlug(route.params.slug)仅在组件初始化时执行一次。当App.vue中异步调用initData()填充store的profiles时,这个ref的值不会自动更新,因为它没有建立与store状态的响应式依赖。- 模板中直接调用
store.getProfileBySlug(...)时,Pinia的getter本身是响应式的,每次组件渲染都会重新执行getter,因此能获取到最新的store数据。
解决方案
将profile从普通ref改为响应式计算属性,让它依赖store的profiles和路由参数,这样当两者变化时会自动更新:
修改后的组件代码:
<script setup> import { computed } from 'vue' // 替换ref为computed import { useProfileStore } from '@/stores/profile' const store = useProfileStore() import { useRoute } from 'vue-router' const route = useRoute() // 使用computed建立响应式依赖 const profile = computed(() => store.getProfileBySlug(route.params.slug)) </script> <template> <div class="record"> <ul> <li><h2>Template</h2><p>{{ store.getProfileBySlug(route.params.slug) }}</p></li> <li><h2>Setup</h2><p>{{ profile }}</p></li> </ul> </div> </template>
备选方案(监听变化手动更新)
如果必须使用ref,可以通过监听store状态或路由参数的变化来手动更新profile的值:
<script setup> import { ref, watch } from 'vue' import { useProfileStore } from '@/stores/profile' const store = useProfileStore() import { useRoute } from 'vue-router' const route = useRoute() const profile = ref() // 监听路由参数和store的profiles变化 watch( () => [route.params.slug, store.profiles], ([newSlug]) => { profile.value = store.getProfileBySlug(newSlug) }, { immediate: true } // 初始化时立即执行一次 ) </script>
关键说明
- Pinia的getter是基于状态的响应式计算属性,直接在模板中使用或通过
computed引用时,会自动追踪依赖并更新。 - 普通
ref如果只做一次性赋值,不会响应后续的状态变化,必须通过computed或watch来建立响应式关联。
内容的提问来源于stack exchange,提问作者allanberry
相关产品推荐
相关产品推荐

