限制 vue/vuex 反应性
Posted
技术标签:
【中文标题】限制 vue/vuex 反应性【英文标题】:Restrict vue/vuex reactivity 【发布时间】:2017-11-02 13:48:21 【问题描述】:假设我们有一些对象数组,这些对象永远不会改变。例如,这可能是从 google maps places api 接收的搜索结果 - 每个结果都是相当复杂的对象,具有 id、title、address、coordinate、photos 和一堆其他属性和方法。
我们想使用 vue/vuex 在地图上显示搜索结果。如果将一些新结果推送到商店,我们希望在地图上绘制它们的标记。如果某些结果被删除,我们要删除它的标记。但在内部,每个结果都不会改变。
有没有办法告诉 vue 跟踪数组(push、splice 等),但不要更深入,也不跟踪它的任何元素的属性?
现在我只能想象一些丑陋的数据拆分 - 将 id 数组保留在 vue 中,并在存储之外有单独的逐个缓存。我正在寻找更优雅的解决方案(如 knockout.js observableArray)。
【问题讨论】:
【参考方案1】:您可以在这些对象上使用Object.freeze()
。这会带来(非常小的!)性能损失,但如果您不一次添加数百或数千个对象,它应该可以忽略不计。
编辑:或者,您可以冻结数组(性能更好),这将使 Vue 跳过“反应”其内容。
当您需要将对象添加到该数组时,请构建一个新的以替换旧的:
state.searchResults = Object.freeze(state.searchResults.concat([item]))
即使对于更大的阵列,这也相当便宜。
【讨论】:
我有一个疑问,如果searchResults[ ]
处于存储状态,并且我们使用组件中的计算属性从存储中获取searchResults[ ]
,vue 将在发生更改时更新该数组长度甚至项目属性的任何更改
使用这两种方法,计算属性将在数组内容发生变化时更新。
如果内部每个结果都没有改变,那么计算属性只会在数组中的任何项目被添加或删除时更新。那么,如果您知道数组中的项目没有改变,为什么还要采取额外的步骤并冻结对象
我用另一种解决方案调整了我的答案,即在添加东西时冻结数组并用新的替换它(因为你不能 push()
到冻结的数组)。
一个就够了。 Vue 在遇到冻结对象时会跳过子对象。【参考方案2】:
乍一看,数据拆分似乎不是这个任务的丑陋解决方案。我们所需要的只是使用 getter 而不是原始的 vuex 状态。我们假设传入的结果是一个数组,其中包含具有唯一 id
字段的任何对象。那么解决方案可能如下所示:
const state =
ids: []
let resultsCache = ;
const getters =
results: function(state)
return _.map(state.ids,id => resultsCache[id]);
const mutations =
replaceResults: function(state,results)
const ids = [];
const cache = ;
(results||[]).forEach((r) =>
if (!cache[r.id])
cache[r.id] = r;
ids.push(r.id);
);
state.ids = ids;
resultsCache = cache;
,
appendResults: function(state,results)
(results||[]).forEach((r) =>
if (!resultsCache[r.id])
resultsCache[r.id] = r;
state.results.push(r.id);
);
export default
getters,
mutations,
namespaced: true
【讨论】:
【参考方案3】:我从 vue 中创建了一个名为 vue-for-babylonians 的分支来限制反应性,甚至允许某些对象属性是反应性的。看看here。
有了它,你可以告诉 Vue 不要让任何存储在 vue 或 vuex 中的对象成为响应式的。您还可以告诉 Vue 使对象属性的某些子集具有响应性。您会发现性能得到了显着提升,并且您可以像在 vue/vuex 中一样享受存储和传递大型对象的便利。
【讨论】:
【参考方案4】:您可以使用shallowRef
来实现此目的。
首先导入它:
import shallowRef from 'vue';
在你的突变中,你可以有这样的突变:
mutations:
setMyObject(state, payload)
state.myObject = shallowRef(payload.value);
,
这将跟踪替换对象,但不跟踪对象属性的更改。
为了完整起见,这里是shallowRef
的文档:
https://v3.vuejs.org/api/refs-api.html#shallowref
【讨论】:
以上是关于限制 vue/vuex 反应性的主要内容,如果未能解决你的问题,请参考以下文章