El manejo del estado global en aplicaciones Vue 3 se simplifica enormemente con Vuex, especialmente cuando múltiples componentes necesitan compartir y modificar datos. A continuación, se detalla cómo integrar y utilizar Vuex en tu proyecto Vue 3, abarcando sus componentes clave: state, mutations, actions y getters.
- Instalación de Vuex Asegúrate de tener un proyecto Vue 3 configurado. Luego, instala la versión compatible de Vuex:
npm install vuex@next --save
O con Yarn:
yarn add vuex@next --save
- Configuración Inicial del Store En Vue 3, la creación del store se adapta a la Composition API. Crea un archivo, por ejemplo
store/index.js, y define tu store:
import { createStore } from 'vuex';
const store = createStore({
state() {
return {
counterValue: 0,
};
},
mutations: {
aumentar(state) {
state.counterValue++;
},
establecerValor(state, payload) {
state.counterValue = payload;
}
},
actions: {
incrementarAsync({ commit }) {
// Simula una operación asíncrona, como una llamada API
setTimeout(() => {
commit('aumentar');
}, 1000);
},
actualizarContador({ commit }, newValue) {
commit('establecerValor', newValue);
}
},
getters: {
dobleContador(state) {
return state.counterValue * 2;
},
contadorFormateado(state) {
return `Valor actual: ${state.counterValue}`;
}
},
});
export default store;
- Integración del Store en la Alpicación Vue Modifica tu archivo de entrada principal (generalmente
main.jsomain.ts) para usar el store configurado:
import { createApp } from 'vue';
import App from './App.vue';
import store from './store'; // Importa tu store
const app = createApp(App);
app.use(store); // Registra Vuex en la aplicación
app.mount('#app');
- Uso de Vuex en Componentes Vue
Acceso al State Utiliza la función useStore de Vuex para acceder al estado desde la Composition API:
<template>
<div>Valor: {{ valorActual }}</div>
</template>
<script setup>
import { useStore } from 'vuex';
import { computed } from 'vue';
const store = useStore();
const valorActual = computed(() => store.state.counterValue);
</script>
Mutations para Cambios Síncronos Llama a commit para ejecutar mutations que modifican el estado de forma síncrona:
<template>
<button @click="incrementar">Aumentar</button>
</template>
<script setup>
import { useStore } from 'vuex';
const store = useStore();
function incrementar() {
store.commit('aumentar');
}
</script>
Actions para Operaciones Asíncronas Usa dispatch para ejecutar actions, ideales para lógica asíncrona como peticiones HTTP:
<template>
<button @click="iniciarIncrementoAsync">Aumentar Asíncronamente</button>
</template>
<script setup>
import { useStore } from 'vuex';
const store = useStore();
function iniciarIncrementoAsync() {
store.dispatch('incrementarAsync');
}
</script>
Getters para Calcular Datos Derivados Accede a los getters para obtener valores calculados a partir del estado:
<template>
<div>Doble del valor: {{ valorDoble }}</div>
<div>{{ valorFormateado }}</div>
</template>
<script setup>
import { useStore } from 'vuex';
import { computed } from 'vue';
const store = useStore();
const valorDoble = computed(() => store.getters.dobleContador);
const valorFormateado = computed(() => store.getters.contadorFormateado);
</script>
- Ayudantes de Vuex (Map Helpers) Vuex proporciona funicones auxiliares para simplificar el mapeo de estado, getters, mutations y actions en componentes, especialmente útil con la Options API, aunque adaptable a Composition API:
useStoreProporciona acceso al store:
import { useStore } from 'vuex';
export default {
setup() {
const miStore = useStore();
return { miStore };
}
}
Mapeo con Composition API (Usando computed y methods) En Vue 3, es más común usar computed para getters y methods para commits/dispatches directamente o con helpers si se prefiere una sintaxis similar a Options API.
Ejemplo con mapState (adaptado):
import { useStore } from 'vuex';
import { computed } from 'vue';
export default {
setup() {
const store = useStore();
// Mapeo de estado
const contador = computed({
get: () => store.state.counterValue,
set: (newValue) => store.commit('establecerValor', newValue)
});
return { contador };
}
}
Ejemplo con mapGetters (adaptado):
import { useStore } from 'vuex';
import { computed } from 'vue';
export default {
setup() {
const store = useStore();
// Mapeo de getters
const dobleValor = computed(() => store.getters.dobleContador);
return { dobleValor };
}
}
Ejemplo con mapMutations (adaptado):
import { useStore } from 'vuex';
export default {
setup() {
const store = useStore();
// Mapeo de mutations
const incrementar = () => store.commit('aumentar');
return { incrementar };
}
}
Ejemplo con mapActions (adaptado):
import { useStore } from 'vuex';
export default {
setup() {
const store = useStore();
// Mapeo de actions
const ejecutarAccionAsync = () => store.dispatch('incrementarAsync');
return { ejecutarAccionAsync };
}
}
- Módulos de Vuex Para aplicaciones más grandes, Vuex soporta módulos para organizar el store:
// store/modules/usuario.js
const state = {
nombreUsuario: 'Invitado',
};
const getters = {
saludoPersonalizado(state) {
return `Hola, ${state.nombreUsuario}!`;
},
};
const mutations = {
establecerNombre(state, payload) {
state.nombreUsuario = payload;
},
};
const actions = {
actualizarNombreUsuario({ commit }, nuevoNombre) {
commit('establecerNombre', nuevoNombre);
},
};
export default {
namespaced: true, // Habilita el namespace para este módulo
state,
getters,
mutations,
actions,
};
Y agrégalo a tu store principal:
// store/index.js
import { createStore } from 'vuex';
import usuarioModule from './modules/usuario';
const store = createStore({
modules: {
usuario: usuarioModule, // Registra el módulo 'usuario'
},
// ... otros estados, mutations, actions, getters globales si los hay
});
export default store;
En un componente, accederías a un módulo con namespace así:
<template>
<div>{{ saludo }}</div>
<button @click="cambiarNombre('Alice')">Cambiar Nombre</button>
</template>
<script setup>
import { useStore } from 'vuex';
import { computed } from 'vue';
const store = useStore();
// Acceso a getter con namespace
const saludo = computed(() => store.getters['usuario/saludoPersonalizado']);
// Ejecución de mutation con namespace
function cambiarNombre(nombre) {
store.commit('usuario/establecerNombre', nombre);
}
// Ejecución de action con namespace
// store.dispatch('usuario/actualizarNombreUsuario', 'Bob');
</script>