Barramento de Eventos para Estado
Para comunicação entre componentes não relacionados, pode-se utilizar um barramento de eventos no Vue.js.
Crie uma instância do barramento:
const EventoCentral = new Vue()
Adicione-a ao protótipo Vue para acesso global:
Vue.prototype.$eventoCentral = EventoCentral
Em um componente, dispare um evento:
this.$eventoCentral.$emit('acao-click', 'mensagem de teste')
Em outro componente, escute o evento:
this.$eventoCentral.$on('acao-click', (dados) => {
this.textoRecebido = dados
})
Vuex: Estado Centralizado
O Vuex fornece um estado reativo centralizado. Para acessá-lo em componentes:
const ComponenteContagem = {
template: `<div>{{ total }}</div>`,
computed: {
total() {
return this.$store.state.total
}
}
}
Use o auxiliar mapState para simplifciar:
import { mapState } from 'vuex'
export default {
computed: mapState({
total: estado => estado.total,
totalAlias: 'total',
totalComLocal(estado) {
return estado.total + this.contagemLocal
}
})
}
Para mapeamento direto de propriedades:
computed: mapState(['total'])
Combine com computed locais usando o operador spread:
computed: {
calculoLocal() { /* ... */ },
...mapState({
// mapeamentos adicionais
})
}
Vuex: Getters com Cache
Getters são semelhantes a propriedades computadas e possuem cache. Exemplo:
const store = new Vuex.Store({
state: {
afazeres: [
{ id: 1, descricao: '...', concluido: true },
{ id: 2, descricao: '...', concluido: false }
]
},
getters: {
afazeresConcluidos: estado => {
return estado.afazeres.filter(item => item.concluido)
}
}
})
Acesse via propriedade compuatda:
computed: {
totalConcluidos() {
return this.$store.getters.totalConcluidos
}
}
Utilize o auxiliar mapGetters:
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters([
'totalConcluidos',
'outroGetter'
])
}
}
Vuex: Mutations para Alterações Síncronas
Mutations são a única forma de alterar o estado do Vuex, e devem ser síncronas.
const store = new Vuex.Store({
state: { contador: 1 },
mutations: {
incrementar(estado) {
estado.contador++
}
}
})
Comite uma mutation:
store.commit('incrementar')
Use payloads para dados adicionais:
mutations: {
incrementar(estado, valor) {
estado.contador += valor
}
}
store.commit('incrementar', 5)
Payloads também podem ser objetos:
mutations: {
incrementar(estado, payload) {
estado.contador += payload.quantidade
}
}
store.commit('incrementar', { quantidade: 5 })
Estilo de commit em objeto:
store.commit({
tipo: 'incrementar',
quantidade: 5
})
Vuex: Actions para Operações Assíncronas
Actions disparam mutations, mas podem ser assíncronas.
const store = new Vuex.Store({
state: { contador: 0 },
mutations: {
incrementar(estado) {
estado.contador++
}
},
actions: {
incrementarAsync(contexto) {
contexto.commit('incrementar')
}
}
})
Desestruture o contexto:
actions: {
incrementarAsync({ commit }) {
commit('incrementar')
}
}
Dispare a action:
store.dispatch('incrementarAsync')
Use payloads de duas maneiras:
store.dispatch('incrementarAsync', { quantidade: 10 })
store.dispatch({ tipo: 'incrementarAsync', quantidade: 10 })
No componente, use mapActions:
import { mapActions } from 'vuex'
export default {
methods: {
...mapActions([
'incrementar',
'incrementarPor'
]),
...mapActions({
adicionar: 'incrementar'
})
}
}
Combine actions com Promises:
actions: {
acaoA({ commit }) {
return new Promise((resolver, rejeitar) => {
setTimeout(() => {
commit('umaMutation')
resolver()
}, 1000)
})
}
}
store.dispatch('acaoA').then(() => { /* ... */ })
Ou com async/await:
actions: {
async acaoA({ commit }) {
commit('dadosObtidos', await obterDados())
},
async acaoB({ dispatch, commit }) {
await dispatch('acaoA')
commit('outrosDados', await obterOutrosDados())
}
}
Vuex: Modules para Organização
Divida o store em módulos:
const moduloA = {
state: { /* ... */ },
mutations: { /* ... */ },
actions: { /* ... */ },
getters: { /* ... */ }
}
const moduloB = {
state: { /* ... */ },
mutations: { /* ... */ },
actions: { /* ... */ }
}
const store = new Vuex.Store({
modules: {
a: moduloA,
b: moduloB
}
})
store.state.a // estado do moduloA
store.state.b // estado do moduloB
Vuex: Plugins para Extensibilidade
Plugins podem escutar mutations:
export default store => {
console.log('Store inicializado')
store.subscribe((mutacao, estado) => {
console.log(mutacao) // formato { tipo, payload }
})
}
Adicione ao store:
const store = new Vuex.Store({
plugins: [meuPlugin]
})
Para persistência local, use o logger embutido:
import createLogger from 'vuex/dist/logger'
const store = new Vuex.Store({
plugins: [createLogger()]
})