1

I have a Pinia store:

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];
    },
  },
});

The load_material action gets an array of objects from the API and stores it to the state.

The state looks like this:

{
    "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
        }
    ]
}

This is my component:

<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>

All this works as expected, if props.machine_id is 2, the div looks like this:

[ { "id": 1, "machine": 2, "order_date": null, "confirm_date": null, "delivery_date": null, "ready": false } ]

No comes the problem, I want to filter the array for objects that have the ready set to true.

If I change the getter to return (machine_id) => state.material[machine_id].filter((m) => m.ready == true); I get an error in the console:

Uncaught (in promise) TypeError: state.material[machine_id] is undefined

I'm completely lost whats going on here and hope somebody can point out what I'm doing wrong

1
  • You missed the await in onMounted. Thats why it gets rendered with undefined. Calling filter on undefined throws the error above. Commented Oct 31, 2023 at 20:47

1 Answer 1

0

Your getter runs immediately and does not wait for your state to load. In your first example, state.material[machine_id] is initially undefined. While your data is being fetched your UI is actually rendering {{ undefined }} which is syntactically legal, but renders nothing. The data arrives sometime later and is rendered as expected. The reason this all works is because you're not trying to do anything to undefined other than return it.

In your second example, state.material[machine_id] is still initially undefined, but now you're trying to call filter() on it, which gives you your error. You can't do this until your state actually has data available to filter.

One solution is to not call your getter until materialStore.material data exists. This can be accomplished with a v-if on your div, checking that the object isn't empty. Only when it's non-empty will it attempt to render which will call your getter, and at that point it will be safe to do so:

<div v-if="Object.keys(materialStore.material).length > 0">
  Ready: {{ materialStore.getReadyMaterial(props.machine_id) }}
</div>
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.