Skip to content
On this page

Definindo uma Memória (store)

Antes de mergulhar dentro dos conceitos fundamentais, nós precisamos saber que uma memória é definida com a utilização de defineStore() e que ela requer um nome único, passado como primeiro argumento:

js
import { defineStore } from 'pinia'
// Tu podes nomear o valor de retorno de `defineStore()` para que quiseres,
// mas é melhor utilizar o nome da memória e envolvê-la com `use` e
// `Store` (por exemplo, `useUserStore`, `useCartStore`, `useProductStore`)
// `useStore`, poderia ser qualquer coisa tipo, `userUser`, `useCart` (remover)
// o primeiro argumento é um identificador único da memória na tua aplicação
export const useStore = defineStore('main', {
  // outras opções...
})
import { defineStore } from 'pinia'
// Tu podes nomear o valor de retorno de `defineStore()` para que quiseres,
// mas é melhor utilizar o nome da memória e envolvê-la com `use` e
// `Store` (por exemplo, `useUserStore`, `useCartStore`, `useProductStore`)
// `useStore`, poderia ser qualquer coisa tipo, `userUser`, `useCart` (remover)
// o primeiro argumento é um identificador único da memória na tua aplicação
export const useStore = defineStore('main', {
  // outras opções...
})

Este nome, também referenciado como id, é necessário e é usado pela Pinia para conectar a memória à ferramenta do programador (devtools, em Inglês). A nomenclatura que a função retornada utiliza... é uma convenção entre os constituíveis (composables, termo em Inglês) para tornar a sua utilização idiomática.

A defineStore() aceita dois valores distintos para o seu segundo argumento: uma função de Configuração ou um objeto de Opções.

Memórias baseadas em Opções

Semelhante a API de Opções da Vue, nós também podemos passar um Objeto de Opções com as propriedades state, actions e getters.

js
export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  getters: {
    double: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++
    },
  },
})
export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  getters: {
    double: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++
    },
  },
})

Tu podes pensar de state (estado) como o data (dados) da memória, e getters (recuperadores) como as propriedades computed (computadas) da memória, e actions (ações) como os methods (métodos).

As memórias baseadas em opções devem ser intuitivas e simples de serem iniciadas.

Memórias baseadas em Composições

Há também uma outra sintaxe possível para definir as memórias. Semelhante a função setup da API de Composição da Vue, nós podemos passar uma função que define propriedades reativas e métodos, e que retorna uma objeto com as propriedades e métodos que nós queremos expor.

js
export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const name = ref('Eduardo')
  const doubleCount = computed(() => count.value * 2)
  function increment() {
    count.value++
  }
  return { count, name, doubleCount, increment }
})
export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const name = ref('Eduardo')
  const doubleCount = computed(() => count.value * 2)
  function increment() {
    count.value++
  }
  return { count, name, doubleCount, increment }
})

Nas Memórias baseadas em Composições:

  • As ref() tornam-se propriedades state
  • As computed() tornam-se getters
  • As function() tornam-se actions

As memórias baseadas composições trazem muito mais flexibilidade do que Memórias baseadas em Opções visto que podes criar observadores dentro de uma memória e utilizar livremente qualquer constituível (composable, termo em Inglês). No entanto, lembra-te de que a utilização de constituíveis tornará Interpretação no Lado do Servidor (SSR, sigla em Inglês) complexa.

Qual sintaxe eu deveria escolher?

De acordo com o artigo que fala sobre a escolha entre a API de Composição e API de Opções da Vue, escolha aquela com a qual estás mais confortável. Se não estiveres certo de qual, experimente primeiro a Memórias baseadas em Opções.

Utilizando a memória

Nós estamos definindo uma memória porque a memória não será criada até que a useStore() seja chamada dentro de setup():

js
import { useCounterStore } from '@/stores/counter'

export default {
  setup() {
    const store = useCounterStore()

    return {
      // retornar uma instância da memória
      // para utilizá-la no modelo de marcação.
      store,
    }
  },
}
import { useCounterStore } from '@/stores/counter'

export default {
  setup() {
    const store = useCounterStore()

    return {
      // retornar uma instância da memória
      // para utilizá-la no modelo de marcação.
      store,
    }
  },
}

Dica

Se ainda não estiveres a utilizar os componentes setup, podes continuar a utilizar a Pinia com os mapas auxiliares.

Tu podes definir quantas memórias que quiseres e deves definir cada memória em um ficheiro diferente para obter o melhor da pinia (tal como permitir a separação de código e fazer inferência de TypeScript do teu pacote automaticamente).

Uma vez que a memória é instanciada, podes acessar diretamente qualquer propriedade state, getters, e actions definida na memória. Nós veremos estes em detalhe nas próximas páginas mas a conclusão automática ajudar-te-á.

Nota que a store é um objeto envolvido com a reactive, querendo dizer que não é preciso escrever .value depois dos recuperadores (getters, em Inglês) mas, tal como as props em setup, nós não podemos desestruturá-las:

js
export default defineComponent({
  setup() {
    const store = useCounterStore()
    // ❌ Isto não funcionará porque quebra a reatividade
    // é o mesmo que desestruturar a partir de `props`
    const { name, doubleCount } = store

    name // "Eduardo"
    doubleCount // 0

    setTimeout(() => {
      store.increment()
    }, 1000)

    return {
      // sempre será "eduardo"
      name,
      // sempre será 0
      doubleCount,
      // também sempre será 0
      doubleNumber: store.doubleCount,

      // ✅ este aqui será reativo
      doubleValue: computed(() => store.doubleCount),
    }
  },
})
export default defineComponent({
  setup() {
    const store = useCounterStore()
    // ❌ Isto não funcionará porque quebra a reatividade
    // é o mesmo que desestruturar a partir de `props`
    const { name, doubleCount } = store

    name // "Eduardo"
    doubleCount // 0

    setTimeout(() => {
      store.increment()
    }, 1000)

    return {
      // sempre será "eduardo"
      name,
      // sempre será 0
      doubleCount,
      // também sempre será 0
      doubleNumber: store.doubleCount,

      // ✅ este aqui será reativo
      doubleValue: computed(() => store.doubleCount),
    }
  },
})

Para extrair propriedades da memória enquanto preserva-se a sua reatividade, precisas utilizar a storeToRefs(). Ela criará referências para todas as propriedades reativas. Isto é útil para quando estiveres apenas utilizando o estado da memória mas não chamando nenhuma ação. Nota que podes desestruturar as ações diretamente da memória visto que elas também estão presas a própria memória:

js
import { storeToRefs } from 'pinia'

export default defineComponent({
  setup() {
    const store = useCounterStore()
    // `name` e `doubleCount` são referências reativas
    // também criará referências 
    // para as propriedades adicionas pelas extensões
    // mas ignorará qualquer ação ou
    // propriedade não reativa e ou referenciada
    const { name, doubleCount } = storeToRefs(store)
    // a ação `increment` já pode ser extraída
    const { increment } = store

    return {
      name,
      doubleCount,
      increment,
    }
  },
})
import { storeToRefs } from 'pinia'

export default defineComponent({
  setup() {
    const store = useCounterStore()
    // `name` e `doubleCount` são referências reativas
    // também criará referências 
    // para as propriedades adicionas pelas extensões
    // mas ignorará qualquer ação ou
    // propriedade não reativa e ou referenciada
    const { name, doubleCount } = storeToRefs(store)
    // a ação `increment` já pode ser extraída
    const { increment } = store

    return {
      name,
      doubleCount,
      increment,
    }
  },
})

Lançado sob a licença MIT.