Vamos criar um app bem simples utilizando o Vuex para entender como utilizá-lo. Para esse exemplo, nós iremos construir um aplicativo onde você pressiona um botão, e ele incrementa um contador.
Nós estaremos utilizando esse simples exemplo para explicar os conceitos, e os problemas que o vuex tenta resolver - como gerenciar um aplicativo complexo que utiliza vários componentes. Considere que esse exemplo utiliza três componentes:
components/App.vue
O elemento raíz, que contém outros dois componentes filhos:
Display
para exibir o valor atual do contador.Increment
que é um botão para incrementar o valor atual.
<template>
<div>
<Display></Display>
<Increment></Increment>
</div>
</template>
<script>
import Display from './Display.vue'
import Increment from './Increment.vue'
export default {
components: {
Display: Display,
Increment: Increment
}
}
</script>
components/Display.vue
<template>
<div>
<h3>Count is 0</h3>
</div>
</template>
<script>
export default {
}
</script>
components/Increment.vue
<template>
<div>
<button>Increment +1</button>
</div>
</template>
<script>
export default {
}
</script>
Increment
e Display
não sabem da existência um do outro, e não podem passar mensagens entre si.App
terá que utilizar events e broadcasts para coordenar os dois componentes.App
é quem coordena os outros componentes, eles não são reutilizáveis e são muito acoplados. Reestruturar o aplicativo pode quebrá-lo.Esses são os passos que serão utilizados:
Isso pode ser um pouco demais para incrementar um contador. Mas note que esses conceitos irão funcionar muito bem em aplicações maiores, melhorando a manutenabilidade e fazendo seu aplicativo mais fácil de debugar e vai te ajudar a manter ele por mais tempo. Então, vamos modificar nosso código para utilizar o Vuex.
O armazém mantém os dados do aplicativo. Todos os componentes utilizam os dados do armazém. Antes de começarmos, instale o Vuex via npm:
$ npm install --save vuex
Crie um novo arquivo em vuex/store.js
import Vue from 'vue'
import Vuex from 'vuex'
// Indique o Vue a utilizar o Vuex
Vue.use(Vuex)
// Nós criamos um objeto para armazenar o valor inicial do estado
// quando o aplicativo for iniciado
const state = {
// TODO: Adicionar o estado inicial
}
// Crie um objeto para armazenar nossas mutações.
const mutations = {
// TODO: adicionar as mutações
}
// Vamos combinar o estado inicial com as mutações para criar um armazém Vuex
// Esse armazém pode ser vinculado ao aplicativo
export default new Vuex.Store({
state,
mutations
})
Nós precisamos informar ao nosso aplicativo sobre esse armazém. Para fazer isso nós simplesmente precisamos alterar nosso componente principal.
Edite o arquivo components/App.vue
e adicione o armazém.
import Display from './Display.vue'
import Increment from './IncrementButton.vue'
import store from '../vuex/store' // importe o armazém que acabamos de criar
export default {
components: {
Display: Display,
Increment: Increment
},
store: store // Adicionando essa linha todos os componentes filhos saberão da existência do armazém
}
Dica: Com ES6 e Babel você pode utilizar da seguinte maneira:
components: { Display, Increment, }, store
A ação é uma função que é chamada no componente. Funções de ação pode disparar atualizações no armazém ao disparar a mutação correta. Uma ação também pode fazer requisições HTTP e ler outros dados do armazém antes de disparar atualizações.
Crie um novo arquivo em vuex/actions.js
com uma simples função chamada incrementCounter
// Uma ação irá receber um armazém como seu primeiro argumento
// Já que estamos apenas interessados em disparar uma mutação
// Nós podemos importar os dois parâmetros utilizando a habilidade de <i>destructuring</i> do ES6
export const incrementCounter = function ({ dispatch, state }) {
dispatch('INCREMENT', 1)
}
E vamos chamar a ação no nosso componente components/Increment.vue
.
<template>
<div>
<button @click='increment'>Increment +1</button>
</div>
</template>
<script>
import { incrementCounter } from '../vuex/actions'
export default {
vuex: {
actions: {
increment: incrementCounter
}
}
}
</script>
Note algumas coisas interessantes que acabamos de adicionar:
vuex.actions
que inclui a nova açãothis.increment()
em qualquer método.@click
, fazendo com que a ação increment
atue como qualquer outro método Vue.incrementCounter
, mas nós podemos utilizar o nome que acharmos mais apropriado.No nosso arquivo vuex/actions.js
nós disparamos uma mutação INCREMENT
mas nós ainda não escrevemos como lidar com isso. Então vamos fazer isso agora.
Edite o arquivo vuex/store.js
const state = {
// Quando o aplicativo iniciar, o valor de count será 0
count: 0
}
const mutations = {
// Uma mutação recebe o estado atual como primeiro parâmetro
// Você pode fazer qualquer modificação dentro desse método
INCREMENT (state, amount) {
state.count = state.count + amount
}
}
Crie um novo arquivo chamado vuex/getters.js
// Esse getter é uma função que simplesmente retorna o valor do contador
// Com o ES6 você pode escrever assim:
// export const getCount = state => state.count
export function getCount (state) {
return state.count
}
Essa função retorna parte do objeto de estado que nos interessa - o valor atual do contador. Nós podemos utilizar esse getter dentro do componente.
Edite o arquivo components/Display.vue
<template>
<div>
<h3>Count is {{ counterValue }}</h3>
</div>
</template>
<script>
import { getCount } from '../vuex/getters'
export default {
vuex: {
getters: {
// note que você está passando uma função, e não o valor 'getCount()'
counterValue: getCount
}
}
}
</script>
Existe um novo objeto chamado vuex.getters
que requisita a função counterValue
para ser vinculada ao getter getCount
. Nós escolhemos diferentes nomes para mostrar que você pode escolher o nome que fizer sentido ao contexto do seu componente, não necessariamente o nome do getter.
Você deve estar se perguntando - por que nós escolhemos utilizar um getter ao invés de acessar diretamente o valor do estado. Esse conceito é mais uma boa prática, e é mais aplicável a uma aplicação mais complexa, e apresenta algumas vantagens:
store.count
para store.counter.value
você só precisa atualizar um getter ao invés de vários arquivos.Esses são apenas alguns dos benefícios de utilizar os getters.
Se você rodar a aplicação, agora você verá ela funcionando como deveria.
Para aumentar seu entendimento sobre o Vuex, você pode tentar implementar as seguintes modificações ao app, como um exercício.
IncrementAmount
e entre com um valor para incrementar o contador. Isso pode ser um pouco diferente, já que os forms no Vuex funcionam de uma forma diferente. Leia o arquivo Manipulações de Formulários para mais detalhes.