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