How to correctly handle information fetch from an API with Pinia in Vue.js 3?
Asked Answered
O

1

14

I'm currently working on a project where to fetch data from an API. I need access to that data all over my app, so I thought that the best option was to use Pinia (usually I used Vuex, but I want to try this "new" store solution).

My "problem" is that I really don't know if the way I achieve my goal is the best way or even a "good practice". In my Pinia store I wrote this:


export const listadoADPs = defineStore("listado", {
  state: () => ({
    adps: [],
  }),
  actions: {
    getADPs() {
      const api =
        "URL";

      fetch(api)
        .then((response) => response.json())
        .then(({ data }) => (this.adps = data))
        .catch((error) => console.log(error));
    },
  },
});

Then, in my component I coded this:

<script setup>
import { ref, computed } from "vue";
import { listadoADPs } from "@/stores/adps";
const store = listadoADPs();

const cards = ref([
  {
    number: computed(() => store.adps.length),
    description: "ADPs vigentes",
  },
  {
    number: computed(
      () => store.adps.filter((adp) => adp.estado_cd === "Suscrito").length
    ),
    description: "Convenios de Desempeño Suscritos",
  },
  {
    number: 0,
    description: "Alertas enviadas",
  },
]);
</script>

Specifically, I don't know if making a computed property for each "number" key in my array "cards" is right, I mean, finally is the same data, so why I can't make just one computed property and save the data in a variable? The thing is that if I work in that way when I reloaded the page, the data just disappears.

Reading the documentation and much more, I think there is a reactivity issue that I still don't understand at all, but I really want to make well this code, so I prefer to ask to you.

Orlina answered 10/3, 2022 at 2:34 Comment(2)
You are asking "how" without explaining "what". I mean how can anyone tell you how to code cards without explaining what is the exact expected format of the data in the cards array - preferably with examples of raw response and expected structure after transformation. Anyway this is not a Pinia specific question...Infrequent
It's unclear what problem you have with reloading. Could be the problem with persistence, or race condition, or else. The question lacks stackoverflow.com/help/mcve . Can store.adps change after it was fetched? If not then nested computeds don't make sense, you could compute the whole cards once. Also getADPs doesn't return a promise that could be chainedSlavocracy
S
7

I would use getters here.

// store.ts
export const listadoADPs = defineStore("listado", {
  state: () => ({
    adps: [],
  }),
  actions: {
    getADPs() {
      const api =
        "URL";

      fetch(api)
        .then((response) => response.json())
        .then(({ data }) => (this.adps = data))
        .catch((error) => console.log(error));
    },
  },
  getters: {
    // BEWARE: getter names cannot be same as state props!
    listadoADPs(state) {
      return state.adps.length;
    },
    adpsFilteredLength(state) {
      return (query: string) => state.adps.filter((adp) => adp.estado_cd === query).length;
    }
  },
});

in your component

<script setup>
import { ref, computed } from "vue";
import { listadoADPs } from "@/stores/adps";
const store = listadoADPs();

const cards = ref([
  {
    number: store.adpsLength,
    description: "ADPs vigentes",
  },
  {
    number: computed( // must be computed because of sending parameter
      () => store.adpsFilteredLength("Suscrito")
    ),
    description: "Convenios de Desempeño Suscritos",
  },
  {
    number: 0,
    description: "Alertas enviadas",
  },
]);
</script>

For persistency this Pinia plugin seems to be nicely done: https://www.npmjs.com/package/pinia-plugin-persist

As others already mentioned I can't help you more without providing more information.

Idealy post reproduciton of your problem ;)

Swordsman answered 4/9, 2022 at 6:43 Comment(2)
@/stores/adps has no exported member named listadoADPs. I needed to use an async getter in my equivalent code. is that not possible?? how can I do the fetch in a get?Rootless
OK apparently I needed to write out the long return type in typescript according to this, it's working when importing the whole store and then using storeToRefs() to extract the getter (not like the above code): pinia.vuejs.org/core-concepts/getters.htmlRootless

© 2022 - 2024 — McMap. All rights reserved.