简体   繁体   English

限制 vue/vuex 反应性

[英]Restrict vue/vuex reactivity

Let's assume we have some array of objects, and these objects never change.假设我们有一些对象数组,这些对象永远不会改变。 For example, that may be search results, received from google maps places api - every result is rather complex object with id, title, address, coordinates, photos and a bunch of other properties and methods.例如,这可能是从谷歌地图地点 api 接收的搜索结果 - 每个结果都是相当复杂的对象,具有 id、标题、地址、坐标、照片和一堆其他属性和方法。

We want to use vue/vuex to show search results on the map.我们想使用 vue/vuex 在地图上显示搜索结果。 If some new results are pushed to the store, we want to draw their markers on the map.如果将一些新结果推送到商店,我们希望在地图上绘制它们的标记。 If some result is deleted, we want to remove its marker.如果某个结果被删除,我们想删除它的标记。 But internally every result never changes.但在内部,每个结果永远不会改变。

Is there any way to tell vue to track the array (push, splice, etc), but not to go deeper and do not track any of its element's properties?有什么方法可以告诉 vue 跟踪数组(推送、拼接等),但不能更深入地跟踪它的任何元素的属性?

For now I can imagine only some ugly data split - keep the array of ids in vue and have separate cache-by-id outside of the store.现在,我只能想象一些丑陋的数据拆分 - 将 id 数组保留在 vue 中,并在商店外按 id 单独缓存。 I'm looking for a more elegant solution (like knockout.js observableArray).我正在寻找更优雅的解决方案(如knockout.js observableArray)。

You can use Object.freeze() on those objects.您可以在这些对象上使用Object.freeze() This comes with a (really tiny!) performance hit, but it should be negligible if you don't add hundreds or thousands of objects at once.这带来了(真的很小!)性能损失,但如果您不一次添加数百或数千个对象,则应该可以忽略不计。

edit: Alternatively, you could freeze the array (much better performance) which will make Vue skip "reactifying" its contents.编辑:或者,您可以冻结数组(更好的性能),这将使 Vue 跳过“重新激活”其内容。

And when you need to add objects to that array, build a new one to replace the old one with:当您需要向该数组添加对象时,请构建一个新对象来替换旧对象:

state.searchResults = Object.freeze(state.searchResults.concat([item]))

That would be quite cheap even for bigger arrays.即使对于更大的阵列,这也非常便宜。

At the second glance data split seems not so ugly solution for this task.乍一看,数据拆分似乎不是这项任务的丑陋解决方案。 All that we need is using getters instead of the raw vuex state.我们所需要的只是使用 getter 而不是原始的 vuex 状态。 We suppose that incoming results is an array with any objects that have unique id field.我们假设传入的结果是一个数组,其中包含具有唯一id字段的任何对象。 Then the solution could look like:那么解决方案可能如下所示:

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
}

I created a fork out of vue called vue-for-babylonians to restrict reactivity and even permit some object properties to be reactive.我从 vue 中创建了一个名为 vue-for-babylonians 的分支来限制反应性,甚至允许一些对象属性是反应性的。 Check it out here .在这里查看

With it, you can tell Vue to not make any objects which are stored in vue or vuex from being reactive.有了它,你可以告诉 Vue 不要让存储在 vue 或 vuex 中的任何对象成为反应性的。 You can also tell Vue to make certain subset of object properties reactive.您还可以告诉 Vue 使对象属性的某些子集具有反应性。 You'll find performance improves substantially and you enjoy the convenience of storing and passing large objects as you would normally in vue/vuex.您会发现性能得到了显着提高,并且您可以像通常在 vue/vuex 中一样享受存储和传递大对象的便利。

You can use shallowRef to achieve this.您可以使用shallowRef来实现这一点。

First import it:首先导入它:

import {shallowRef} from 'vue';

In your mutations you can have a mutation like this:在您的突变中,您可以有这样的突变:

mutations: {
    setMyObject(state, payload) {
      state.myObject = shallowRef(payload.value);
    },
}

This will track replacing the object, but not changes to the objects properties.这将跟踪替换对象,但不会跟踪对象属性的更改。

For completeness here is the documentation to shallowRef :为了完整shallowRef这里是shallowRef的文档:

https://v3.vuejs.org/api/refs-api.html#shallowref https://v3.vuejs.org/api/refs-api.html#shallowref

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM