Vuex
Compreendendo o problema que ele resolve
Quando você está construindo uma aplicação baseada no browser não é incomum perder o controle sobre o fluxo da informação que é gerenciada pela app.
Nestes tipos de aplicação os dados não são apenas o que o usuário envia ao servidor mas também o que controla a exibição de controles de interface. Então - por exemplo - você modifica um valor num componente e outro componente que deveria estar visível agora está escondido. Isso se chama efeito colateral.
Conforme sua aplicação cresce torna-se um pesadelo lidar com todos os efeitos colaterais que aparecem. A forma mais comum de compartilhar dados através da árvore de componentes é utilizando eventos, acima e abaixo na árvore. Isso é OK quando você captura um evento imediatamente após dispara-lo mas quando o evento é capturado mais acima ou mais abaixo na árvore, você rapidamente se pegará pensando ”- mas de onde veio este evento?”.
Single Source of Truth
Single Source of Truth (ou Fonte Única da Verdade) é estruturar seus dados de maneira que este não são duplicados em nenhum lugar da app. Pense nela como a espinha dorsal da aplicação. Todos os componentes pegarão os dados dela e salvarão de volta, tornando muito mais fácil saber de onde a alteração veio.
Há algumas vantagens ao se adotar esta abordagem:
- Você tem um local centralizado para adicionar/modificar seus dados;
- Está disponível para todos os componentes;
- Nenhum componente modifica a informação diretamente, garantindo a consistência dos dados;
- Ferramentas adicionais fazem do desenvolvimento uma experiência melhor.
###Vuex Documentação oficial aqui
É a implementação feita pela equipe Vue.js para o Flux, que é a implementação feita pelo Facebook da Single Source of Truth. A integração com o sistema reativo do Vue é transparente e requer apenas algumas configurações bem simples, ficando imediatamente pronto para uso.
O primeiro passo é instalar utilizando npm install vuex --save-dev
. Logo em seguida vá ao arquivo no qual você criou sua instância do Vue Object, instrua o Vue para usar o Vuex e adicione a Store ao objeto:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
new Vue({
el: 'body',
store: new Vuex.Store({})
})
Dentro do método Vuex.Store() você terá que passar um objeto com duas propriedades, como segue:
- O State, que é um objeto comum Javascript, contendo os dados que você quer compartilhar através da aplicação;
- Os métodos que alteram o State. Eles são chamados de Mutation Methods.
Como example veja o trecho de código:
...
new Vue({
el: 'body',
store: new Vuex.Store({
state: {
user: {
name: '',
email: ''
}
},
mutations: {
SET_USER (store, obj) {
store.user = obj.user
}
}
})
})
Como você deve ter imaginado tanto a quantidade de propriedades em State quanto a de métodos em Mutations crescerá bastante. Usemos então o module bundler (Webpack, por exemplo) para fazer o setup do Vuex em algum outro local em nosso File System e então importa-lo:
criar o arquivo: /src/vuex/store.js
import Vue from 'vue'
import Vuex from 'Vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
user: {
name: '',
email: ''
}
},
mutations: {
SET_USER (store, obj) {
store.user = obj.user
}
}
})
e no seu /src/main.js:
import Vue from 'vue'
import store from './vuex/store'
Vue.use(Vuex)
new Vue({
el: 'body',
store
})
###Lendo e gravando dados na Store
Agora que temos nossa store totalmente configurada e anexada ao objeto Vue é hora de começar a utiliza-la.
A beleza da coisa é que a Store estará automaticamente disponível a todos os componentes. Da mesma forma que você está acostumado a usar propriedades tais como methods: {}, data: {} and computed: {} agora você também terá vuex: {}.
<script>
export default {
props: ['some-property-here'],
vuex: {
getters: {},
actions: {}
},
data () { // << some local state
return {
whatever: ''
}
}
}
</script>
Se se quer acessar a propriedade user da Vuex Store basta simplesmente criar um getter…
...
vuex: {
getters: {
user: store => store.user
},
actions: {}
},
...
… e então utilizar como uma propriedade interna do componente: this.user
.
Agora você precisa modificar os dados do usuário. Antes de seguirmos adiante uma nota mental: você NÃO PODE modificar o State diretamente. Se me perguntar se é possível eu diria “sim é” porém altamente desencorajado. Isso por que se quiser saber o que acontece quando qualquer propriedade for modificada, basta ir no único local onde isso acontece, ao invés de abrir todos os seus componentes para só então descobrir de onde a alteração partiu.
Então, como modificar os dados?
Utilizando actions. Elas são métodos como os que você costuma criar dentro de methods: {} em seus componentes mas você os declara num local especial: dentro de vuex: { actions: {} }. Ao fazer isso você se assegura de que o primeiro parâmetro recebido pelo método será uma instância da Vuex Store.
Estamos interessados num método do objeto Store chamado dispatch(). Usaremos este método para invocar a Mutation, método responsável por setar os dados na Vuex Store.
...
vuex: {
getters: {
user: store => store.user
},
actions: {
setUser ({dispatch}, obj) {
dispatch('SET_USER', obj)
}
}
},
methods: {
ordinaryButtonClickHandler () {
let user = {
user: {
username: 'New username',
email: 'email@email.com'
}
}
this.setUser(user) // << a action é executada por um clique num botão, por ex.
}
}
...
Preste atenção a esta parte pois é a mais confusa: dispatch('SET_USER', obj)
. Primeiro recebemos este método dispatch() ao utilizar Destructuring Assignment, um novo e muito útil recurso do ES2015. Pense no método dispatch() como um event dispatcher com um único objetivo: invocar uma mutation. Você não precisa captura-lo manualmente como faria com um evento comum. Graças ao Vue ele vai diretamente para o objeto de mutations na sua configuração do Vuex e então o método adequado é invocado.
O nome do método da mutation é o primeiro parâmetro e o objeto que a mutation receberá é o segundo. Quando chegar à mutation a Store é finalmente modificada e todos os componentes observando a Store serão automaticamente atualizados.
Ferramentas de Suporte ao Desenvolvimento
Existe uma ferramenta muito poderosa que dá suporte ao desenvolvimento com Vue.js. Ela se chama Vue Devtools e é uma extensão para o Google Chrome. Permite que você inspecione sua árvore de componentes, interagindo com eles no Console. Lhe permite também interagir com Vuex Store, tirando vantagem do recursos chamado Time Travel Debugging: mostra todas as mutations que foram executadas permitindo navegar entre elas e vendo alterações na aplicação em tempo real.
Conclusão
A documentação oficial diz que Vuex não é adequado para todos os tipo de projeto mas eu acho um recurso tão útil e simples de usar que atualmente incluo em todos os meus projetos. Simplesmente me parece algo natural de ser feito.
Agora que está claro que Vuex é um local centralizado para armazenar seus dados, o que torna muito mais fácil gerenciar o estado da sua aplicação, tenha em mente que você também pode (e deve) manter o estado local dos seus componentes. A decisão sobre o que pertence à Store central ou ao state interno do componente é você quem deve tomar. Se você precisa daquele pedaço de informação em algum outro local da aplicação então você deve adicionar à Vuex Store.