Vuex Mapping Getter с аргументом-кэшируется?
Вот пример магазина Vuex с параметризованным геттером, который мне нужно сопоставить с экземпляром Vue для использования в шаблоне.
const store = new Vuex.Store({
state: {
lower: 5,
higher: 10,
unrelated: 3
},
getters: {
inRange: state => value => {
console.log('inRange run')
return (state.lower <= value) && (state.higher >= value)
}
},
mutations: {
reduceLower: state => state.lower--,
incrementUnrelated: state => state.unrelated++
}
})
new Vue({
el: '#app',
template: "<div>{{ inRange(4) }}, {{ unrelated }}</div>",
store,
computed: Object.assign(
Vuex.mapGetters(['inRange']),
Vuex.mapState(['unrelated'])
),
})
setTimeout(function() {
console.log('reduceLower')
store.commit('reduceLower')
setTimeout(function() {
console.log('incrementUnrelated')
store.commit('incrementUnrelated')
}, 3000);
}, 3000);
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuex/dist/vuex.js"></script>
<div id="app"></div>
Во-первых, это действительно кажется допустимым, рабочий код. Однако, учитываяcomputed
должен быть кэшированным набором вычисляемых свойств, мне интересно поведение в этом сценарии, происходит ли кэширование? Если нет, есть ли проблема производительности, чтобы рассмотреть? Даже если функция не вызывает изменения состояния, должен ли это быть method
?
Это анти-паттерн? Пример не настоящий, но я хочу централизовать логику в магазине.
ОБНОВЛЕНИЕ
Я обновил пример, чтобы проиллюстрировать, что модификации базового lower/higher
значения, на котором inRange
значение, которое не является частью вычисления, если сопоставленный геттер был кэширован, изменение несвязанного значения не должно вызывать повторный вызов геттера, однако это происходит.
Мой вывод заключается в том, что нет кэширования, поэтому это имеет более низкую производительность, чем обычное вычисляемое свойство, однако оно по-прежнему функционально корректно.
Вопрос остается открытым относительно того, есть ли какой-либо недостаток в этом шаблоне, или один доступный, который работает лучше.


Ответы - Vuex Mapping Getter с аргументом-кэшируется? / Vuex Mapping Getter with Argument - Cached?

15.06.2017 11:31:43
На мой взгляд это анти-паттерн. Это странный способ направить метод. Кроме того, нет, здесь нет кэширования, так inRange
немедленно возвращает значение (конечная функция) без использования каких - либо членов в state
-поэтому Vue обнаруживает 0 реактивных зависимостей.
Геттеры не могут быть параметризованы таким образом, они могут только выводить вещи, которые основаны на состоянии. Поэтому, если диапазон может храниться в состоянии, это будет работать (и будет кэшироваться).
Аналогичный вопрос здесь: vuexjs getter с аргументом
Поскольку вы хотите централизовать это поведение - я думаю, что вы должны просто сделать это в отдельном модуле, возможно, как миксин. Это также не будет кэшироваться, поэтому вам придется обернуть его (и вход) в computed
или использовать какую-то другую memoization
Что-то вроде этого:
import { inRange } from './state/methods';
import { mapGetters } from 'vuex';
const Example = Vue.extend({
data: {
rangeInput: 10
},
computed: {
...mapGetters(['lower', 'higher']),
inRange() {
return inRange(this.rangeInput, this.lower, this.higher);
}
}
});

I think you should just do this in a separate module, perhaps as a mixin.
- моя версия реального мира фактически находится в модуле, однако, поскольку модуль является подразделением магазина,любое решение в контексте модуля должно работать и для магазина. Я не сторонник решения mixin, поскольку оно имеет статическую область и не дает преимуществ над моим решением. Также ваш связанный вопрос очень слабо связан с этим, я не вижу его актуальности.

state/methods.js
-файл будет централизованным местом для хранения логики. Насколько мне известно, Vuex не предлагает способа разоблачения простых методов, поэтому я думаю, что вам нужно использовать модуль вне парадигмы Vuex. Что касается связанного вопроса, это просто более глубокое погружение в то, почему геттеры не могут получать входные данные, кроме самого состояния.



inRange
из шаблона с разными литеральными параметрами, поэтому создание вычисляемого свойства для каждого из них (с данными / состоянием) не подходит для моего варианта использования, но это правильный ответ на вопрос здесь.

17.06.2017 09:01:09
Просто чтобы проиллюстрировать, почему я принял ответ Мэтта, вот рабочий фрагмент, ключевой момент, чтобы заметить, вместо того, чтобы:
Vuex.mapGetters(['inRange'])
Существует истинное вычисляемое свойство:
inRange4: function() {
return this.$store.getters.inRange(4);
}
Это, как видно из выполнения фрагмента кода, привело к правильному кэшированию значения. Как я уже сказал, этот шаблон не тот, который я могу использовать, поскольку я бы в конечном итоге получил слишком много вычисляемых свойств (inRange1, inRange2, inRange3 и т. д.), Однако он отвечает на вопрос с рассматриваемым примером.
Я решил продолжить использовать код из вопроса, без изменений .
Примечание: ответ Мэтта не соответствует этому коду точно, и я считаю, что его намерение состояло в том, что состояние из магазина будет сопоставлено с экземпляром Vue, который я считаю ненужным.
const store = new Vuex.Store({
state: {
lower: 5,
higher: 10,
unrelated: 3
},
getters: {
inRange: state => value => {
console.log('inRange run')
return (state.lower <= value) && (state.higher >= value)
}
},
mutations: {
reduceLower: state => state.lower--,
incrementUnrelated: state => state.unrelated++
}
})
new Vue({
el: '#app',
template: "<div>{{ inRange4 }}, {{ unrelated }}</div>",
store,
computed: Object.assign(
{
inRange4: function() {
return this.$store.getters.inRange(4);
}
},
Vuex.mapState(['unrelated'])
),
})
setTimeout(function() {
console.log('reduceLower')
store.commit('reduceLower')
setTimeout(function() {
console.log('incrementUnrelated')
store.commit('incrementUnrelated')
}, 3000);
}, 3000);
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuex/dist/vuex.js"></script>
<div id="app"></div>

16.09.2019 05:57:52
Кажется, есть способ обойти это, создать карту с вычисленными значениями и получить к ней доступ как
inrange[4];
Я часто использую его для инициализации различных видов доступа, я получаю массив из своего бэкэнда и должен получить доступ к нему по какому-то полю (например, ID). Для приведенного выше примера это кажется разумным, так как диапазон невелик:
const store = new Vuex.Store({
state: {
lower: 5,
higher: 10,
unrelated: 3
},
getters: {
inRange: state => {
console.log('inRange run')
var result = {};
for( var i = state.lower; i < state.higher; i++) {
result[i] = true;
}
return result;
}
},
mutations: {
reduceLower: state => state.lower--,
incrementUnrelated: state => state.unrelated++
}
})
new Vue({
el: '#app',
template: "<div>{{ inRange[4] }}, {{ unrelated }}</div>",
store,
computed: Object.assign(
{
inRange: function() {
return this.$store.getters.inRange;
}
},
Vuex.mapState(['unrelated'])
),
})
setTimeout(function() {
console.log('reduceLower')
store.commit('reduceLower')
setTimeout(function() {
console.log('incrementUnrelated')
store.commit('incrementUnrelated')
}, 3000);
}, 3000);
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuex/dist/vuex.js"></script>
<div id="app"></div>