Vue 中使用 Pinia,如果打开多个相同页面但使用不同的参数来获取数据,出现数据被覆盖的问题,通常是由于 Pinia 的状态共享机制导致的。Pinia 的状态是全局单例的,因此同一个 store 的状态会被所有使用它的组件共享。如果不加以区分,不同参数获取的数据可能会互相覆盖。
以下是解决问题的方法:
解决方案 1:为每个页面实例化独立的数据(按参数区分数据存储)
在 Pinia 的 store 中,可以将数据存储为一个对象,通过参数作为 key 来区分不同页面的数据。
示例代码
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// store.js import { defineStore } from "pinia"; export const useDataStore = defineStore("dataStore", { state: () => ({ dataMap: {} // 存储多个页面的数据,key 是参数 }), actions: { async fetchData(key, params) { // 模拟数据获取逻辑 const data = await fakeApiCall(params); this.dataMap[key] = data; // 按 key 存储数据 } } }); // 模拟接口调用 async function fakeApiCall(params) { return new Promise((resolve) => { setTimeout(() => resolve(`Data for ${params}`), 1000); }); } |
使用示例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<template> <div> <h1>Page {{ id }}</h1> <p>{{ data }}</p> </div> </template> <script> import { useDataStore } from "@/stores/dataStore"; import { onMounted, computed } from "vue"; import { useRoute } from "vue-router"; export default { setup() { const route = useRoute(); const id = route.params.id; // 从路由参数获取 id const dataStore = useDataStore(); onMounted(() => { dataStore.fetchData(id, id); // 以 id 作为 key 获取数据 }); // 按 id 获取对应的数据 const data = computed(() => dataStore.dataMap[id]); return { id, data }; } }; </script> |
工作原理
• 每个页面用参数(如 id)作为 key,在 store 的 dataMap 中存储各自的数据。
• 页面访问时,从 dataMap 按 key 获取对应的数据,不会互相覆盖。
解决方案 2:在组件中使用局部状态管理
如果数据仅在组件中使用,可以避免使用全局状态管理(Pinia),改用组件的局部状态。
示例代码
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<template> <div> <h1>Page {{ id }}</h1> <p>{{ data }}</p> </div> </template> <script> import { ref, onMounted } from "vue"; import { useRoute } from "vue-router"; export default { setup() { const route = useRoute(); const id = route.params.id; // 从路由参数获取 id const data = ref(null); const fetchData = async (id) => { // 模拟数据获取逻辑 data.value = await fakeApiCall(id); }; onMounted(() => { fetchData(id); }); return { id, data }; } }; // 模拟接口调用 async function fakeApiCall(id) { return new Promise((resolve) => { setTimeout(() => resolve(`Data for ${id}`), 1000); }); } </script> |
解决方案 3:动态创建独立的 Store 实例
Pinia 支持动态创建 store 实例,可以为每个页面创建独立的 store。每次打开页面时,创建一个新的实例,避免状态共享。
示例代码
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import { defineStore } from "pinia"; export const createDynamicStore = (id) => defineStore(`store_${id}`, { state: () => ({ data: null }), actions: { async fetchData(params) { // 模拟数据获取逻辑 this.data = await fakeApiCall(params); } } }); // 使用示例 import { createPinia } from "pinia"; import { createDynamicStore } from "@/stores/dataStore"; const pinia = createPinia(); const store = createDynamicStore("page1"); store(pinia).fetchData("page1"); |
选择适合的解决方案
• 方案 1(推荐):适用于需要全局管理不同页面的数据。
• 方案 2:适用于简单的页面逻辑,数据仅限于当前组件。
• 方案 3:适用于高度动态的场景,需要为每个页面创建独立的 store 实例。
根据你的项目需求选择合适的方案,确保数据管理合理且不相互覆盖。