在Pinia中如何持久化存储带函数的对象

在使用 Pinia 进行状态管理时,常规方法难以直接持久化存储包含函数的对象。因为 JSON.stringify()在序列化对象时会忽略函数。本文将介绍一种自定义的解决方案,实现包含函数对象的持久化。

1. 安装依赖

确保项目中已经安装了 Pinia。如果没有安装,可以通过 npm 进行安装:

1
npm install pinia

2. 自定义持久化逻辑

实现自定义的持久化逻辑,通过将函数序列化为字符串存储,在恢复时再转换回函数。

代码示例

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import { defineStore } from "pinia";

// 自定义持久化逻辑
const loadState = () => {
const state = localStorage.getItem("myStore");
if (state) {
const parsedState = JSON.parse(state);
// 将存储的函数字符串转换回函数
if (
parsedState.myObject &&
typeof parsedState.myObject.sayHello === "string"
) {
parsedState.myObject.sayHello = new Function(
`return ${parsedState.myObject.sayHello}`
)();
}
return parsedState;
}
return null;
};

const saveState = (state) => {
// 将函数转换为字符串存储
const stateToSave = { ...state };
if (
stateToSave.myObject &&
typeof stateToSave.myObject.sayHello === "function"
) {
stateToSave.myObject.sayHello = stateToSave.myObject.sayHello.toString();
}
localStorage.setItem("myStore", JSON.stringify(stateToSave));
};

// 定义包含函数的对象
const myObjectWithFunction = {
message: "Hello from Pinia!",
sayHello: function () {
console.log(this.message);
},
};

// 定义Pinia存储
export const useMyStore = defineStore("myStore", {
state: () => {
const savedState = loadState();
return (
savedState || {
myObject: myObjectWithFunction,
}
);
},
actions: {
updateMessage(newMessage) {
this.myObject.message = newMessage;
saveState(this.$state);
},
},
// 在存储更新时调用保存逻辑
onBeforeUpdate: () => {
saveState(useMyStore().$state);
},
});

3. 在组件中使用

在 Vue 3 组件中使用上述定义的 Pinia 存储。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
<div>
<button @click="callFunctionInObject">Call Function in Object</button>
<input v-model="newMessage" placeholder="Enter new message" />
<button @click="updateMessage">Update Message</button>
</div>
</template>

<script setup>
import { ref } from "vue";
import { useMyStore } from "./store";

const store = useMyStore();
const newMessage = ref("");

const callFunctionInObject = () => {
store.myObject.sayHello();
};

const updateMessage = () => {
store.updateMessage(newMessage.value);
};
</script>

注意事项

  1. 安全风险:使用new Function()存在安全风险,如果存储的函数字符串来自不可信源,可能会执行恶意代码。
  2. 复杂场景:函数序列化可能无法处理所有复杂情况,如函数内部引用了外部变量。

通过上述方法,我们能够在 Pinia 中实现包含函数对象的持久化存储,解决常规持久化方案无法处理函数的问题。