Diretório do Armazém de Estado
O diretório store
contém os ficheiros do nosso armazém de estado de Vuex. O armazém de estado da Vuex é fornecido com a Nuxt de origem, mas está desativada por predefinição. A criação de um ficheiro index.js
neste diretório ativa o armazém de estado.
A utilização de um armazém de estado para gerir o estado é importante para todas as grandes aplicações. É por isto que a Nuxt implementa a Vuex no seu núcleo.
Ativar o Armazém de Estado
O Nuxt irá procurar pelo diretório store
. Se ele conter um ficheiro, que não seja um ficheiro oculto ou um ficheiro README.md
, então a memória será ativada. Isto significa que o Nuxt irá:
A Nuxt procurará pelo diretório store
. Se conter um ficheiro, que não é um ficheiro oculto ou um ficheiro README.md
, então o armazém de estado será ativado. Isto significa que a Nuxt:
- Importará a Vuex
-
Adicionará a opção
store
à instância raiz do Vue.
Módulos
Cada ficheiro .js
no diretório store
é transformado num módulo nominal (sendo index
o módulo raiz). O nosso valor state
deve ser sempre uma function
para evitar estado partilhado indesejado no lado do servidor.
Para começarmos, exportamos o estado (state
), como uma função (function
) e os recuperadores (getters
), mutações (mutations
) e ações (actions
) como objetos (object
):
export const state = () => ({
counter: 0
})
export const getters = {
getCounter(state) {
return state.counter
}
}
export const mutations = {
increment(state) {
state.counter++
}
}
export const actions = {
async fetchCounter({ state }) {
// requisitar
const res = { data: 10 };
state.counter = res.data;
return res.data;
}
}
Então, podemos ter um ficheiro store/todos.js
:
export const state = () => ({
list: []
})
export const mutations = {
add(state, text) {
state.list.push({
text,
done: false
})
},
remove(state, { todo }) {
state.list.splice(state.list.indexOf(todo), 1)
},
toggle(state, todo) {
todo.done = !todo.done
}
}
O armazém de estado será criado como tal:
new Vuex.Store({
state: () => ({
counter: 0
}),
mutations: {
increment(state) {
state.counter++
}
},
modules: {
todos: {
namespaced: true,
state: () => ({
list: []
}),
mutations: {
add(state, { text }) {
state.list.push({
text,
done: false
})
},
remove(state, { todo }) {
state.list.splice(state.list.indexOf(todo), 1)
},
toggle(state, { todo }) {
todo.done = !todo.done
}
}
}
}
})
E no nosso pages/todos.vue
, ao usar o módulo todos
:
<template>
<ul>
<li v-for="todo in todos" :key="todo.text">
<input :checked="todo.done" @change="toggle(todo)" type="checkbox">
<span :class="{ done: todo.done }">{{ todo.text }}</span>
</li>
<li><input @keyup.enter="addTodo" placeholder="What needs to be done?"></li>
</ul>
</template>
<script>
import { mapMutations } from 'vuex'
export default {
computed: {
todos () {
return this.$store.state.todos.list
}
},
methods: {
addTodo (e) {
this.$store.commit('todos/add', e.target.value)
e.target.value = ''
},
...mapMutations({
toggle: 'todos/toggle'
})
}
}
</script>
<style>
.done {
text-decoration: line-through;
}
</style>
O método do módulo também funciona para definições de alto nível sem implementar um sub-diretório no diretório do armazém de estado.
Exemplo para o estado (state
): criamos um ficheiro store/state.js
e adicionamos o seguinte:
export default () => ({
counter: 0
})
E os recuperadores (getters
) correspondentes podem estar no ficheiro store/getters.js
:
export default {
getCounter(state) {
return state.counter
}
}
E as mutações (mutations
) correspondentes podem estar no ficheiro store/mutations.js
:
export default {
increment(state) {
state.counter++
}
}
E as ações (actions
) correspondentes podem estar no ficheiro store/actions.js
:
export default {
async fetchCounter({ state }) {
// requisitar
const res = { data: 10 };
state.counter = res.data;
return res.data;
}
}
Exemplo de estrutura de pasta
Uma estrutura complexa de ficheiros ou pastas de configuração do armazém de estado pode ter o seguinte aspeto:
store/
--| index.js
--| ui.js
--| shop/
----| cart/
------| actions.js
------| getters.js
------| mutations.js
------| state.js
----| products/
------| mutations.js
------| state.js
------| itemsGroup1/
--------| state.js
Extensões no Armazém de Estado
Podemos adicionar extensões adicionais ao armazém de estado, colocando-os no ficheiro store/index.js
:
import myPlugin from 'myPlugin'
export const plugins = [myPlugin]
export const state = () => ({
counter: 0
})
export const mutations = {
increment(state) {
state.counter++
}
}
Mais informações sobre as extensões: documentação da Vuex .
A Ação nuxtServerInit
Se a ação nuxtServerInit
estiver definida no armazém de estado e o modo for universal
, a Nuxt a chamará com o contexto (somente do lado do servidor). É útil quando temos alguns dados no servidor que queremos fornecer diretamente ao lado do cliente.
Por exemplo, digamos que temos sessões no lado do servidor e podemos aceder ao utilizador conectado através da req.session.user
. Para adicionar o utilizador autenticado ao nosso armazém de estado, atualizamos o nosso store/index.js
para o seguinte:
actions: {
nuxtServerInit ({ commit }, { req }) {
if (req.session.user) {
commit('user', req.session.user)
}
}
}
store/index.js
) receberá esta ação. Temos de encadear as ações do nosso módulo a partir daí.O contexto é fornecido a nuxtServerInit
como o segundo argumento no método asyncData
.
Se o nuxt generate
for executado, a nuxtServerInit
será executada para cada rota dinâmica gerada.
nuxtServerInit
devem retornar uma promessa (Promise
) ou utilizar async
e await
para permitir o servidor da Nuxt esperar por estas.actions: {
async nuxtServerInit({ dispatch }) {
await dispatch('core/load')
}
}
Modo Estrito da Vuex
O modo estrito é ativado por predefinição no modo de desenvolvimento e desativado no modo de produção. Para desativar o modo estrito no desenvolvimento, sigamos o exemplo abaixo em store/index.js
:
export const strict = false