yerigagarin
yerigagarin

Reputation: 177

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

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.

Upvotes: 14

Views: 24388

Answers (1)

Luckylooke
Luckylooke

Reputation: 4539

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

Upvotes: 7

Related Questions