我有一家 Pinia 商店:
import { defineStore } from "pinia";
import { api } from "@/services/api";
export const useMaterialStore = defineStore("material", {
state: () => ({
material: {},
}),
actions: {
async load_material(machine_id) {
const response = await api.get("material/machine/" + machine_id);
console.log(response.data);
this.material[machine_id] = response.data;
},
},
getters: {
getReadyMaterial: (state) => {
return (machine_id) => state.material[machine_id];
},
},
});
load_material
操作从 API 获取对象数组并将其存储到状态。
状态看起来像这样:
{
"2": [
{
"id": 1,
"machine": 2,
"order_date": null,
"confirm_date": null,
"delivery_date": null,
"ready": false
}
],
"4": [
{
"id": 2,
"machine": 4,
"order_date": null,
"confirm_date": null,
"delivery_date": "2023-10-30",
"ready": true
},
{
"id": 3,
"machine": 4,
"order_date": null,
"confirm_date": null,
"delivery_date": null,
"ready": false
}
]
}
这是我的组件:
<template>
<div>Ready: {{ materialStore.getReadyMaterial(props.machine_id) }}</div>
</template>
<script setup>
import { onMounted } from "vue";
import { useMaterialStore } from "@/store/material";
const materialStore = useMaterialStore();
const props = defineProps({
machine_id: Number,
});
onMounted(() => {
materialStore.load_material(props.machine_id);
});
</script>
所有这些都按预期工作,如果
props.machine_id
是 2
,则 div 看起来像这样:
[ { "id": 1, "machine": 2, "order_date": null, "confirm_date": null, "delivery_date": null, "ready": false } ]
不,问题来了,我想过滤数组中
ready
设置为 true
的对象。
如果我将 getter 更改为
return (machine_id) => state.material[machine_id].filter((m) => m.ready == true);
,我会在控制台中收到错误:
Uncaught (in promise) TypeError: state.material[machine_id] is undefined
我完全迷失了这里发生的事情,希望有人能指出我做错了什么
您的 getter 会立即运行,不会等待您的状态加载。在第一个示例中,
state.material[machine_id]
最初是未定义的。当你的数据被获取时,你的 UI 实际上正在渲染 {{ undefined }}
,这在语法上是合法的,但什么也不渲染。数据稍后到达并按预期呈现。这一切之所以有效,是因为除了归还它之外,您没有尝试对 undefined
做任何事情。
在第二个示例中,
state.material[machine_id]
最初仍然是未定义的,但现在您尝试在其上调用 filter()
,这会给您带来错误。在您所在的州确实有可用于过滤的数据之前,您无法执行此操作。
一种解决方案是在
materialStore.material
数据存在之前不要调用 getter。这可以通过 div 上的 v-if
来完成,检查对象是否为空。只有当它非空时,它才会尝试渲染,这将调用你的 getter,此时这样做是安全的:
<div v-if="Object.keys(materialStore.material).length > 0">
Ready: {{ materialStore.getReadyMaterial(props.machine_id) }}
</div>