[Из песочницы] Vuex — чрезмерное использование геттеров в приложении. Разбор ошибки
В этой статье пойдет речь об распространенной ошибке, которую делают большинство начинающих при разработке приложения на Vue + Vuex. Мы поговорим о геттерах (getters) и как их правильно использовать. Также мы рассмотрим вспомогательные функции mapState и mapGetters.
Примечания перед прочтением: рекомендуется иметь базовые знания Vue и Vuex.
Глава 1. Что такое геттеры. Пример нецелесообразного использования
Геттеры — это часть хранилища Vuex, которые возвращают вычисляемые данные текущего состояния хранилища нашим компонентам.
Рассмотрим пример:
const store = new Vuex.Store({
state: {
// список книг
books: [
{ id: 1, title: '...', finished: true },
{ id: 2, title: '...', finished: false }
]
},
getters: {
// возвращаем список всех книг
books: state => state.books
}
});
Так будет выглядеть компонент со списком всех книг:
export default {
computed: {
// наш геттер
books() {
return this.$store.getters.books
}
}
}
Пример выше работает, но так делать не стоит. Этим подходом мы перегружаем приложение.
Если вам нужно вывести данные напрямую из хранилища к компоненту без каких-либо модификаций — геттеры не самое лучшее решение. Дальше я покажу, как можно улучшить код и избавиться от нецелесообразного использования геттеров.
Глава 2. Использование mapState для получения данных из хранилища
Документация гласит:
Когда компонент должен использовать множество свойств или геттеров хранилища, объявлять все эти вычисляемые свойства может быть утомительно. В таких случаях можно использовать функцию mapState, которая автоматически генерирует вычисляемые свойства.
Давайте вернемся к нашему компоненту и используем mapState вместо геттера:
import { mapState } from 'vuex';
export default {
computed: {
...mapState([
'books'
])
}
}
Геттер из хранилища можно удалить, т.к. мы в нем больше не нуждаемся:
const store = new Vuex.Store({
state: {
// список книг
books: [
{ id: 1, title: '...', finished: true },
{ id: 2, title: '...', finished: false }
]
}
});
Намного удобнее, не так ли? Мы избавились от ненужных геттеров и сократили количество кода.
Глава 3. Зачем же нужны геттеры, если есть mapState
И все таки они нужны. Геттеры используются в тех случаях, когда нужно вывести модифицированную информацию из хранилища (например список всех прочитанных книг).
Давайте создадим геттер, чтобы получить все прочитанные книги из хранилища:
const store = new Vuex.Store({
state: {
// список книг
books: [
{ id: 1, title: '...', finished: true },
{ id: 2, title: '...', finished: false }
]
},
getters: {
// возвращаем список прочитанных книг
finishedBooks: state => {
return state.books.filter(books => books.finished);
}
}
});
Теперь наш компонент будет выглядеть так:
import { mapState } from 'vuex';
export default {
computed: {
// получаем список всех книг
...mapState([
'books'
]),
// получаем список прочитанных книг
finishedBooks() {
return this.$store.getters.finishedBooks
}
}
}
На этом можно было бы остановиться, но есть еще одна полезная вещь, которую стоит знать. Если вам нужно переиспользовать один и тот же геттер в разных компонентах, может быть не совсем удобно прописывать геттеры каждый раз в методе computed. На помощь приходит mapGetters.
Давайте рассмотрим пример:
// не забываем про импорт
import { mapState, mapGetters } from 'vuex';
export default {
computed: {
// получаем список всех книг
...mapState([
'books'
]),
// получаем список геттеров, или в
// нашем случае список всех прочитанных книг
...mapGetters([
'finishedBooks'
])
}
}
Улучшение налицо: использовав mapGetters мы сократили количество кода.
Вы так же можете вычислить информацию из хранилища основываясь на каких-то данных, например достать книгу по её id или названию. Этого можно добиться передав аргумент нашему геттеру.
const store = new Vuex.Store({
state: {
// список книг
books: [
{ id: 1, title: '...', finished: true },
{ id: 2, title: '...', finished: false }
]
},
getters: {
// возвращаем список прочитанных книг
finishedBooks: state => {
return state.books.filter(books => books.finished);
},
// возвращаем книгу по id
getBookById: (state) => (id) => {
return state.books.find(books => books.id === id)
}
}
});
import { mapState, mapGetters } from 'vuex';
export default {
computed: {
...mapState([
'books'
]),
...mapGetters([
'finishedBooks',
'getBookById'
]),
getBook() {
// получаем книгу с id === this.id
return this.getBookById(this.id)
}
}
}
Закрепление материала
- Вы можете использовать геттеры в своих действиях (actions) vuex или непосредственно в компонентах.
- Результаты геттера обновляются при изменении одной из зависимостей.
- Геттерам можно передавать дополнительные аргументы, чтобы проводить вычисления данных на их основе.
- Используйте геттеры только для вычисления нетривиальных данных, которые требуются в нескольких компонентах, в иных случаях используйте вспомогательную функцию mapState.
Документация по геттерам на русском
Пример приложения из статьи на codepen