Capítulo 13: Gerenciamento de Estado Global Oficial com Pinia (defineStore)

Especialização em Front-End com Vue • Vue 3 & Nuxt 3 • Composition API, Pinia, Vue Router, SSR e TypeScript


🗺️ Mapa Conceitual da Arquitetura Pinia

flowchart TD
    A["Aplicação Vue 3 (createPinia())"] --> B["Store Pinia: defineStore('id', () => { ... })"]

    subgraph SETUP_STORE["Setup Store (Estilo Composition API)"]
        C["State: ref() e reactive()"]
        D["Getters: computed()"]
        E["Actions: Funções síncronas ou assíncronas"]
    end

    B --- SETUP_STORE

    C & D -->|"storeToRefs(store): Desestruturação Segura"| F["Componente Consumidor A"]
    E -->|"Desestruturação Direta de Ações"| F
    B -->|"Reatividade Compartilhada"| G["Componente Consumidor B"]

    subgraph RECURSOS["Vantagens sobre o Vuex"]
        H["Zero Mutations (Atribuição Direta)"]
        I["Suporte Nativo Total ao TypeScript"]
        J["DevTools com Time-Travel Debugging"]
        K["Modular por Padrão (Sem Namespaces complexos)"]
    end

    SETUP_STORE --- RECURSOS

    style A fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px
    style B fill:#fff3e0,stroke:#ff9800,stroke-width:2px
    style SETUP_STORE fill:#ede7f6,stroke:#7e57c2,stroke-width:2px
    style F fill:#e8f5e9,stroke:#4caf50,stroke-width:2px

🏛️ 1. O Estado Global Oficial: Pinia

O Pinia é a biblioteca oficial de gerenciamento de estado do Vue 3, substituindo o antigo Vuex. Ele foi arquitetado para tirar pleno proveito do sistema de reatividade baseado em Proxy, oferecendo uma API extremamente concisa, tipagem TypeScript completa sem anotações complexas e suporte completo a SSR (Nuxt 3).

1.1 Fim das Mutações: Mutações Diretas e Claras

No Vuex, qualquer alteração de estado exigia a criação de uma Mutation síncrona com commits textuais (commit('SET_USER', payload)), o que gerava grande volume de código repetitivo e suscetível a erros de digitação. No Pinia:

  • Não existem mutations: O estado pode ser modificado diretamente no corpo de uma action ou até mesmo dentro de um componente (store.count++).
  • DevTools Integradas: Toda alteração direta continua sendo rastreada com precisão milimétrica nas Vue DevTools, incluindo suporte a Time-Travel Debugging.

1.2 Option Stores vs Setup Stores

O Pinia suporta duas sintaxes de criação:

  1. Option Stores: Similar à Options API do Vue 2 (state: () => ({ ... }), getters: { ... }, actions: { ... }).
  2. Setup Stores (Padrão Ouro): Utiliza exatamente a mesma sintaxe da Composition API:
    • ref() define o State.
    • computed() define os Getters.
    • Funções regulares definem as Actions.

1.3 Desestruturação Segura com storeToRefs()

Um dos erros mais comuns de iniciantes é desestruturar propriedades de uma store diretamente (const { user, token } = useAuthStore()). Isso quebra a ligação reativa do Proxy!

  • A Regra: Sempre utilize storeToRefs(store) para desestruturar propriedades de estado (state) e cálculos derivados (getters).
  • Ações: As funções (actions) são imutáveis e podem ser desestruturadas diretamente sem o auxílio do storeToRefs.

⚖️ 2. Tabela Comparativa: Vuex 4 vs Pinia

Critério de Comparação Vuex 4 (Legado) Pinia (Moderno / Oficial)
Arquitetura de Mutações Exige mutations síncronas obrigatórias. Zero mutations; mutações diretas em actions.
Integração com TypeScript Complexa; exige módulos tipados manualmente. Inferência automática 100% de tipos e retornos.
Estrutura de Módulos Árvore única aninhada com namespaced: true. Stores independentes e modulares por arquivo.
Tamanho do Pacote (Bundle) ~10 KB. ~1.5 KB (extremamente leve e tree-shakeable).
Suporte à Composition API Parcial via adapters. Nativo de primeira classe com Setup Stores.

⚠️ 3. Armadilhas Comuns em Produção (Gotchas & Anti-Patterns)

Anti-Pattern 1: Desestruturar State sem storeToRefs

Erro Comum:

// ❌ QUEBRA DE REATIVIDADE
const authStore = useAuthStore();
const { currentUser } = authStore; // currentUser agora é estático! O template não atualizará.

Abordagem Correta: const { currentUser } = storeToRefs(authStore);.

Anti-Pattern 2: Chamar a Store fora do Ciclo de Instalação do App

Erro Comum: Executar const store = useAuthStore(); no nível raiz de um arquivo .ts antes de app.use(pinia). Abordagem Correta: Invoque a função use...Store() dentro de funções executadas após o bootstrap da aplicação (dentro de componentes, guards de rota ou funções de serviço).


💻 4. Código Conceitual Arquitetural Comentado

// src/stores/userSessionStore.ts
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';

export interface UserProfile {
  id: string;
  name: string;
  role: 'ADMIN' | 'DEV' | 'AUDITOR';
}

export const useUserSessionStore = defineStore('userSession', () => {
  // 1. STATE (Refs Reativos)
  const currentUser = ref<UserProfile | null>(null);
  const authToken = ref<string | null>(null);

  // 2. GETTERS (Computed Properties)
  const isAuthenticated = computed<boolean>(() => authToken.value !== null);
  const isAdmin = computed<boolean>(() => currentUser.value?.role === 'ADMIN');

  // 3. ACTIONS (Funções com mutação de estado e chamadas de I/O)
  function setSession(user: UserProfile, token: string): void {
    currentUser.value = user;
    authToken.value = token;
  }

  function clearSession(): void {
    currentUser.value = null;
    authToken.value = null;
  }

  return {
    currentUser,
    authToken,
    isAuthenticated,
    isAdmin,
    setSession,
    clearSession
  };
});

🛠️ 5. Cheat-Sheet do Pinia

// 1. Instalação e Bootstrap
import { createPinia } from 'pinia';
app.use(createPinia());

// 2. Consumo em Componente SFC
import { storeToRefs } from 'pinia';
import { useUserSessionStore } from '@/stores/userSessionStore';

const sessionStore = useUserSessionStore();

// Desestruturação de dados com storeToRefs:
const { currentUser, isAuthenticated } = storeToRefs(sessionStore);

// Desestruturação direta de ações:
const { setSession, clearSession } = sessionStore;