Gerenciamento de Estado em Vue 3 com Vuex

Introdução ao Vuex

Vuex é uma biblioteca de gerenciamento de estado para aplicações Vue.js. Ele implementa um armazenamento centralizado para todos os componentes da aplicação, garantindo que o estado seja gerenciado de forma previsível. Seu design segue o padrão arquitetural Flux.

Conceitos Fundamentais

  • State (Estado): A única fonte de verdade que contém todos os dados da aplicação. É uma estrutura de dados única (árvore) que alimenta os componentes Vue.
  • Getters (Derivações): Funções que derivam informações do estado central. Atuam como propriedades computadas do store, permitindo o cálculo e filtragem de dados.
  • Mutations (Mutações): São os únicos responsáveis por modificar o estado. Devem ser funções síncronas e rastreáveis.
  • Actions (Ações): Semelhantes a mutações, mas podem conter operações assíncronas (chamadas API, temporizadores). Elas "comprometem" (commit) mutações em vez de alterar o estado diretamente.
  • Modules (Módulos): Permitem dividir o store Vuex em módulos separados e auto-contidos, cada um com seu próprio state, getters, mutations e actions.

Configuração Inicial

Para adicionar o Vuex a um projeto Vue 3 baseado em Vite ou Vue CLI, instale-o via seu gerenciador de pacotes:

npm install vuex@next --save

Em seguida, crie um diretório store no src e defina o arquivo index.js ou index.ts. A estrutura básica é:

import { createStore } from 'vuex';

export const store = createStore({
 state: {
   // Dados globais aqui
 },
 getters: {
   // Derivações do estado
 },
 mutations: {
   // Funções síncronas para alterar o estado
 },
 actions: {
   // Lógica assíncrona, despacha mutações
 },
 modules: {
   // Módulos organizacionais
 }
});

Por fim, injete o store na instância da aplicação Vue em main.js:

import { createApp } from 'vue';
import App from './App.vue';
import { store } from './store';

const app = createApp(App);
app.use(store);
app.mount('#app');

Utilizando o Vuex na Prática

1. Acessando o Estado (State)

Defina propriedades no objeto state.

// store/index.js
state: {
 contador: 0
}

Acesse o estado diretamente nos componnetes via a propriedade computada $store.state.

<template>
 <div>
   <p>Valor global: {{ $store.state.contador }}</p>
 </div>
</template>

2. Criando Derivações (Getters)

Os getters são funções que recebem o state como primeiro argumento e podem receber outros getters como segundo.

// store/index.js
getters: {
 contadorDuplicado(state) {
   return state.contador * 2;
 },
 ehPar(state) {
   return state.contador % 2 === 0;
 }
}

Acesse-os como propriedades computadas do store.

<template>
 <div>
   <p>Contador x2: {{ $store.getters.contadorDuplicado }}</p>
   <p v-if="$store.getters.ehPar">O valor é par.</p>
 </div>
</template>

3. Atlerando Estado com Mutações (Mutations)

As mutações são as únicas funções que podem alterar o estado. Elas são chamadas usando commit.

// store/index.js
mutations: {
 INCREMENTA_CONTADOR(state, valor) {
   state.contador += valor;
 }
}
<template>
 <div>
   <p>{{ $store.state.contador }}</p>
   <button @click="incrementar">Somar 5</button>
 </div>
</template>

<script>
export default {
 methods: {
   incrementar() {
     // 'commit' chama a mutação. O primeiro argumento é seu nome, o segundo é o payload.
     this.$store.commit('INCREMENTA_CONTADOR', 5);
   }
 }
}
</script>

4. Lidando com Lógica Assíncrona (Actions)

As actions são perfeitas para operações assíncronas. Elas despacham mutações usando commit após a conclusão.

// store/index.js
actions: {
 atualizarContadorAsync({ commit }, payload) {
   // Simula uma chamada de API
   setTimeout(() => {
     commit('INCREMENTA_CONTADOR', payload);
   }, 1000);
 }
}

As actions são chamadas com dispatch.

<script>
export default {
 methods: {
   incrementarAsync() {
     // 'dispatch' chama a action
     this.$store.dispatch('atualizarContadorAsync', 10);
   }
 }
}
</script>

5. Organizando com Módulos

Para aplicações maiores, divida o store em módulos.

// store/modules/autenticacao.js
export default {
 namespaced: true, // Opcional, mas recomendado para evitar conflitos
 state: () => ({
   usuario: null,
   token: ''
 }),
 mutations: {
   SET_USUARIO(state, user) {
     state.usuario = user;
   }
 },
 actions: {
   login({ commit }, credenciais) {
     // Lógica de login...
     const usuarioFake = { nome: 'João', email: credenciais.email };
     commit('SET_USUARIO', usuarioFake);
   }
 }
}

// store/index.js
import moduloAutenticacao from './modules/autenticacao';

export const store = createStore({
 modules: {
   auth: moduloAutenticacao
 }
});

Acesse os dados do módulo usando o caminho completo.

<template>
 <div v-if="$store.state.auth.usuario">
   Bem-vindo, {{ $store.state.auth.usuario.nome }}
 </div>
</template>

Para actions e mutations de módulos com namespaced: true, use o caminho no dispatch ou commit.

this.$store.dispatch('auth/login', { email: 'teste@email.com', senha: '123' });

Tags: Vue 3 Vuex Gerenciamento de Estado Módulos Vuex Actions

Publicado em 6-16 03:32 por Thomas