Vuex Mapping Getter с аргументом-кэшируется?

Vuex Mapping Getter с аргументом-кэшируется?

15.06.2017 10:53:06 Просмотров 44 Источник

Вот пример магазина 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значение, которое не является частью вычисления, если сопоставленный геттер был кэширован, изменение несвязанного значения не должно вызывать повторный вызов геттера, однако это происходит.

Мой вывод заключается в том, что нет кэширования, поэтому это имеет более низкую производительность, чем обычное вычисляемое свойство, однако оно по-прежнему функционально корректно.

Вопрос остается открытым относительно того, есть ли какой-либо недостаток в этом шаблоне, или один доступный, который работает лучше.

У вопроса есть решение - Посмотреть?

https://stackoverflow.com/questions/44575886/vuex-mapping-getter-with-argument-cached#comment76201420_44575886
Мне также нужно кэшировать мои геттеры с аргументами. Я до сих пор не знаю, как это сделать.
https://stackoverflow.com/questions/44575886/vuex-mapping-getter-with-argument-cached#comment76202387_44575886
Я немного развил ответ Мэтта (пришлось добавить еще один ответ для него): stackoverflow.com/a/44607740/1084004

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

Является ответом!
Matt

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);
    }
  }
});
https://stackoverflow.com/questions/44575886/vuex-mapping-getter-with-argument-cached/44576534#comment76142347_44576534
Спасибо за ввод, у вас есть пример предпочтительного шаблона для достижения этой цели? I think you should just do this in a separate module, perhaps as a mixin.- моя версия реального мира фактически находится в модуле, однако, поскольку модуль является подразделением магазина,любое решение в контексте модуля должно работать и для магазина. Я не сторонник решения mixin, поскольку оно имеет статическую область и не дает преимуществ над моим решением. Также ваш связанный вопрос очень слабо связан с этим, я не вижу его актуальности.
https://stackoverflow.com/questions/44575886/vuex-mapping-getter-with-argument-cached/44576534#comment76142532_44576534
@mikeapr4 смотрите обновленный ответ для примера. state/methods.js-файл будет централизованным местом для хранения логики. Насколько мне известно, Vuex не предлагает способа разоблачения простых методов, поэтому я думаю, что вам нужно использовать модуль вне парадигмы Vuex. Что касается связанного вопроса, это просто более глубокое погружение в то, почему геттеры не могут получать входные данные, кроме самого состояния.
https://stackoverflow.com/questions/44575886/vuex-mapping-getter-with-argument-cached/44576534#comment76144135_44576534
@mikeapr4 смешанные вычисляемые значения (и методы) имеют доступ к хранилищу таким же образом, как и любой компонент. Я не уверен, что вы подразумеваете под статической областью.
https://stackoverflow.com/questions/44575886/vuex-mapping-getter-with-argument-cached/44576534#comment76148032_44576534
Честно говоря, я следую чисто функциональному подходу, это интересное решение. @BertEvans-теперь я следую подходу mixin, игнорирую мою статическую точку обзора, я думал о чем-то другом.
https://stackoverflow.com/questions/44575886/vuex-mapping-getter-with-argument-cached/44576534#comment76166485_44576534
Если сегодня нет других ответов, я отмечу это как принятое. В моем случае я делаю несколько вызовов inRangeиз шаблона с разными литеральными параметрами, поэтому создание вычисляемого свойства для каждого из них (с данными / состоянием) не подходит для моего варианта использования, но это правильный ответ на вопрос здесь.
mikeapr4

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>

Samuel Åslund

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>

Закрыть X