title | description |
---|---|
Хранилище Vuex |
Использование единого хранилища для управления состоянием приложения важно для любого крупного проекта, поэтому nuxt.js в своём ядре использует Vuex. |
Использование единого хранилища для управления состоянием приложения важно для любого крупного проекта, поэтому nuxt.js в своём ядре использует Vuex.
Если Nuxt.js обнаруживает каталог store
, происходит следующее:
- Импортируется Vuex
- Модуль
vuex
добавляется в сборку vendors - Опция
store
добавляется к корневому экземпляруVue
.
Nuxt.js позволяет выбрать один из двух подходов при работе с хранилищем:
- Обыкновенный:
store/index.js
возвращает экземпляр хранилища - Модульный: каждый
.js
-файл в папкеstore
считается модулем с пространством имён (index
считается корневым модулем)
Для использования хранилища в обычном режиме, мы создаём файл store/index.js
и экспортируем экземпляр хранилища:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = () => new Vuex.Store({
state: {
counter: 0
},
mutations: {
increment (state) {
state.counter++
}
}
})
export default store
Нет необходимости отдельно устанавливать
vuex
— он идёт в комплекте с nuxt.js
Теперь в наших компонентах можно использовать this.$store
:
<template>
<button @click="$store.commit('increment')">{{ $store.state.counter }}</button>
</template>
Nuxt.js позволяет использовать каждый файл в директории
store
как отдельный модуль хранилища.
Если вы хотите использовать этот подход, экспортируйте в store/index.js
состояние, мутации и действия, а не экземпляр хранилища:
export const state = () => ({
counter: 0
})
export const mutations = {
increment (state) {
state.counter++
}
}
Предположим, у нас есть модуль store/todos.js
:
export const state = () => ({
list: []
})
export const mutations = {
add (state, text) {
state.list.push({
text,
done: false
})
},
toggle (state, todo) {
todo.done = !todo.done
}
}
И в pages/todos.vue
мы используем модуль todos
:
<template>
<ul>
<li v-for="todo in todos">
<input type="checkbox" :checked="todo.done" @change="toggle(todo)">
<span :class="{ done: todo.done }">{{ todo.text }}</span>
</li>
<li><input placeholder="What needs to be done?" @keyup.enter="addTodo"></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>
Модули, экспортирующие экземпляр хранилища, использовать тоже можно — но подключать их придётся вручную.
Метод
fetch
используется для заполнения хранилища перед рендерингом страницы. Он похож на методdata
, но не устанавливает данные компонента.
Метод fetch
, если он указан, вызывается каждый раз перед загрузкой компонента (вышесказанное справедливо только для компонентов-страниц). Он может быть вызван как при рендеренге на сервере, так и при переходе по ссылке на клиенте.
Метод fetch
получает в качестве первого аргумента контекст. Чтобы сделать метод асинхронным, верните промис — nuxt.js дождётся его разрешения перед тем как рендерить компонент.
Пример pages/index.vue
:
<template>
<h1>Звёзды: {{ $store.state.stars }}</h1>
</template>
<script>
export default {
fetch ({ store, params }) {
return axios.get('http://my-api/stars')
.then((res) => {
store.commit('setStars', res.data)
})
}
}
</script>
Чтобы сделать код чище, можно использовать async/await:
<template>
<h1>Звёзды: {{ $store.state.stars }}</h1>
</template>
<script>
export default {
async fetch ({ store, params }) {
let { data } = await axios.get('http://my-api/stars')
store.commit('setStars', data)
}
}
</script>
Чтобы увидеть список доступных ключей в context
, взгляните на документацию api контекста страницы.
Если действие nuxtServerInit
определено для хранилища, nuxt.js вызовет его в рамках контекста (только на сервере). Это может быть полезным, если у нас есть данные на сервере, которые мы хотим передать клиентскому приложению напрямую.
Например, предположим что у нас есть хранилище сессий и мы можем получить доступ к пользователю через req.authUser
. Чтобы указать данные о пользователе в хранилище, добавьте в store/index.js
следующий код:
actions: {
nuxtServerInit ({ commit }, { req }) {
if (req.authUser) {
commit('user', req.authUser)
}
}
}
Контекст передаётся в nuxtServerInit
в качестве второго параметра. В целом метод работает так же как data
или fetch
, за исключением того, что context.redirect()
и context.error()
опускаются.