首页 > 解决方案 > Vue,如何处理深度嵌套对象的反应性

问题描述

我有一个我正在操作的对象,如下所示:

const posts = [
    { key1: "abc", key2: [{ innerKey1: "def", innerKey2: 123 }, { innerKey1: "def", innerKey2: 123 }] },
    { key1: "abc", key2: [{ innerKey1: "def", innerKey2: 123 }, { innerKey1: "def", innerKey2: 123 }] },
    { key1: "abc", key2: [{ innerKey1: "def", innerKey2: 123 }, { innerKey1: "def", innerKey2: 123 }] },
];

posts[0].key2[1].innerKey1 = "newVal";

Array inkey2是一个道具,内部键预计会发生变化。我想在innerKey1innerKey2改变时保持反应性。

因为 Vue 很难检测到这里讨论的数组和对象的变化,所以我们不能直接通过索引修改数组或直接通过键修改对象。

为了保持反应性,我们似乎需要一些复杂的逻辑来使用Vue.set()set newVal

我的思路是这样的:

Vue.set(posts, 1, Vue.set(key2, 0, Vue.set(innerKey1, "newVal")))

这是在这里保持反应性的最佳方式,还是我缺少一些可以使这更容易的东西?

注意:我还尝试在我的子组件中使用深度观察器来观察key2数组中发生的变化。但它似乎无法观察到这些变化。

//ChildComponent.vue
<html>
  <div>
   <RandomComponent v-for="thing in key2" :key... :innerKey2="thing.innerKey2">
  </div>
</html>

<script>
props: {
    key2: {
        type: Array,
        require: true,
    },
},
watch: {
    key2: {
        immediate: true,
        deep: true,
        handler () {
            console.log("Watcher working"); //Does not fire when parent mutates innerKeys
        },
    },
},
</script>

标签: javascriptvue.jsvue-reactivity

解决方案


我觉得这个问题不够明确。

  • 如果您只想更新现有数组元素的属性,按索引变异应该可以正常工作,无需任何解决方法。

即这应该是反应性的

posts[0].key2[1].innerKey1 = "newVal";
  • 但是,如果您尝试替换数组元素,则需要解决此处解释的 Vue 反应性问题

我认为您的情况最干净的解决方法是使用Array.splice替换元素。(例如网络响应后)

  const postId = 0 // the root element 
  const updatePost = { ...this.posts[postId] }
  updatePost.key2[1].innerKey1 = 'newVal'

  this.posts.splice(postId, 1, updatedPost);

这是我在codesanbox上做的一个插图


推荐阅读