Skip to content
En esta página

Getters

Los getters son exactamente el equivalente de los valores computados para el estado de un almacén. Pueden estar definidos con la propiedad gettersen defineStore(). Primero reciben el estado como primer parámetro para fomentar el uso de funciones de flecha:

js
export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    doubleCount: (state) => state.count * 2,
  },
})
export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    doubleCount: (state) => state.count * 2,
  },
})

La mayoría del tiempo, los getters solo dependerán del estado. Sin embargo, puede que necesiten usar otros getters. Debido a esto, podemos acceder a toda la instancia del almacén a través de this cuando definimos una función regular, pero es necesario definir el tipo del valor retornado (en TypeScript). Esto es debido a una conocida limitación en TypeScript y no afecta a getters definidos con funciones de flecha ni a getters que no usan this:

ts
export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    // deduce automáticamente el tipo como número
    doubleCount(state) {
      return state.count * 2
    },
    // el tipo retornado **tiene que** estar explícitamente puesto
    doublePlusOne(): number {
      // autocompletado y tipado para todo el almacén ✨
      return this.doubleCount + 1
    },
  },
})
export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    // deduce automáticamente el tipo como número
    doubleCount(state) {
      return state.count * 2
    },
    // el tipo retornado **tiene que** estar explícitamente puesto
    doublePlusOne(): number {
      // autocompletado y tipado para todo el almacén ✨
      return this.doubleCount + 1
    },
  },
})

Entonces puedes acceder al getter directamente desde la instancia del almacén:

vue
<script setup>
import { useCounterStore } from './counterStore'

const store = useCounterStore()
</script>

<template>
  <p>Double count is {{ store.doubleCount }}</p>
</template>
<script setup>
import { useCounterStore } from './counterStore'

const store = useCounterStore()
</script>

<template>
  <p>Double count is {{ store.doubleCount }}</p>
</template>

Acceder a otros getters

Como en las propiedades computadas, puedes combinar multiples getters. Accede a cualquier otro getter con this. Incluso si no quieres usar TypeScript puedes pedir sugerencias a tu IDE para tipos con JSDoc:

js
export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    // el tipo es deducido automáticamente porque no estamos 
    // usando `this`
    doubleCount: (state) => state.count * 2,
    // aquí necesitamos añadir el tipo nosotros (usando JSDoc en 
    // JS). También podemos usar esto para documentar el getter
    /**
     * Devuelve el valor del contador multiplicado por dos más uno.
     *
     * @returns {number}
     */
    doubleCountPlusOne() {
      // autocompletion ✨
      return this.doubleCount + 1
    },
  },
})
export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    // el tipo es deducido automáticamente porque no estamos 
    // usando `this`
    doubleCount: (state) => state.count * 2,
    // aquí necesitamos añadir el tipo nosotros (usando JSDoc en 
    // JS). También podemos usar esto para documentar el getter
    /**
     * Devuelve el valor del contador multiplicado por dos más uno.
     *
     * @returns {number}
     */
    doubleCountPlusOne() {
      // autocompletion ✨
      return this.doubleCount + 1
    },
  },
})

Pasar argumentos a los getters

Los getters son solo propiedades computadas detrás de cámaras, así que no es posible pasarles ningún parámetro. Sin embargo, puedes retornar una función desde el getter para aceptar cualquier argumento:

js
export const useStore = defineStore('main', {
  getters: {
    getUserById: (state) => {
      return (userId) => state.users.find((user) => user.id === userId)
    },
  },
})
export const useStore = defineStore('main', {
  getters: {
    getUserById: (state) => {
      return (userId) => state.users.find((user) => user.id === userId)
    },
  },
})

y usarlos en un componente:

vue
<script>
import { storeToRefs } from 'pinia'
import { useUserListStore } from './store'

const userList = useUserListStore()
const { getUserById } = storeToRefs(userList)
// nota: tendrás que usar `getUserById.value` para acceder
// a la función en el <script setup>
</script>

<template>
  <p>User 2: {{ getUserById(2) }}</p>
</template>
<script>
import { storeToRefs } from 'pinia'
import { useUserListStore } from './store'

const userList = useUserListStore()
const { getUserById } = storeToRefs(userList)
// nota: tendrás que usar `getUserById.value` para acceder
// a la función en el <script setup>
</script>

<template>
  <p>User 2: {{ getUserById(2) }}</p>
</template>

Cabe aclarar que cuando hacemos esto los getters ya no se almacenan en caché, son simplemente funciones que puedes invocar. Sin embargo puede almacenar en caché algunos resultados dentro del propio getter, lo cual no es muy común pero debería demostrar un mayor rendimiento:

js
export const useStore = defineStore('main', {
  getters: {
    getActiveUserById(state) {
      const activeUsers = state.users.filter((user) => user.active)
      return (userId) => activeUsers.find((user) => user.id === userId)
    },
  },
})
export const useStore = defineStore('main', {
  getters: {
    getActiveUserById(state) {
      const activeUsers = state.users.filter((user) => user.active)
      return (userId) => activeUsers.find((user) => user.id === userId)
    },
  },
})

Acceder a getters de otros almacenes

Para usar getters de otros almacenes puedes usarlos directamente dentro del getter:

js
import { useOtherStore } from './other-store'

export const useStore = defineStore('main', {
  state: () => ({
    // ...
  }),
  getters: {
    otherGetter(state) {
      const otherStore = useOtherStore()
      return state.localData + otherStore.data
    },
  },
})
import { useOtherStore } from './other-store'

export const useStore = defineStore('main', {
  state: () => ({
    // ...
  }),
  getters: {
    otherGetter(state) {
      const otherStore = useOtherStore()
      return state.localData + otherStore.data
    },
  },
})

Uso con setup()

Puedes acceder directamente a cualquier getter como una propiedad del almacén (exactamente igual que las propiedades del estado):

vue
<script setup>
const store = useCounterStore()

store.count = 3
store.doubleCount // 6
</script>
<script setup>
const store = useCounterStore()

store.count = 3
store.doubleCount // 6
</script>

Uso con la API de Opciones

Para los próximos ejemplos puedes suponer que el siguiente almacén fue creado:

js
// Ruta de ejemplo:
// ./src/stores/counter.js

import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    doubleCount(state) {
      return state.count * 2
    },
  },
})
// Ruta de ejemplo:
// ./src/stores/counter.js

import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  getters: {
    doubleCount(state) {
      return state.count * 2
    },
  },
})

Con setup()

Dado que la API de composición no es para todo el mundo, el hook setup() puede hacer que trabajar con Pinia sea más fácil con la API de opciones. ¡No necesitas funciones map helper adicionales!

vue
<script>
import { useCounterStore } from '../stores/counter'

export default defineComponent({
  setup() {
    const counterStore = useCounterStore()

    // **solo retorna el almacén entero** en vez de desestructurarlo
    return { counterStore }
  },
  computed: {
    quadrupleCounter() {
      return this.counterStore.doubleCount * 2
    },
  },
})
</script>
<script>
import { useCounterStore } from '../stores/counter'

export default defineComponent({
  setup() {
    const counterStore = useCounterStore()

    // **solo retorna el almacén entero** en vez de desestructurarlo
    return { counterStore }
  },
  computed: {
    quadrupleCounter() {
      return this.counterStore.doubleCount * 2
    },
  },
})
</script>

Esto es útil mientras migras un componente desde la API de opciones a la API de composición pero solo debe haber un paso de migración, siempre intenta evitar mezclar ambos estilos de API en el mismo componente.

Sin setup()

Puedes usar la misma función mapState() usada en la sección anterior del estado para mapear los getters:

js
import { mapState } from 'pinia'
import { useCounterStore } from '../stores/counter'

export default {
  computed: {
    // da acceso a this.doubleCount dentro del componente
    // igual que leerlo desde store.doubleCount
    ...mapState(useCounterStore, ['doubleCount']),
    // igual que lo de arriba pero registrándolo como this.myOwnName
    ...mapState(useCounterStore, {
      myOwnName: 'doubleCount',
      // también puedes escribir una función que de acceso al almacén
      double: (store) => store.doubleCount,
    }),
  },
}
import { mapState } from 'pinia'
import { useCounterStore } from '../stores/counter'

export default {
  computed: {
    // da acceso a this.doubleCount dentro del componente
    // igual que leerlo desde store.doubleCount
    ...mapState(useCounterStore, ['doubleCount']),
    // igual que lo de arriba pero registrándolo como this.myOwnName
    ...mapState(useCounterStore, {
      myOwnName: 'doubleCount',
      // también puedes escribir una función que de acceso al almacén
      double: (store) => store.doubleCount,
    }),
  },
}

Lanzado bajo la Licencia MIT.