首页 > 解决方案 > Vue子组件道具未更新

问题描述

在所有其他问题中,我发现数据被用于防止反应。这里没有使用数据,道具本身无法在渲染中更新。

我的 VueX 功能是:

addItemColumn()在第一个 Box 中创建一个新列,本质上是不允许框自行增长;但是,父级可以请求添加一个新列(到第一个框)。

MoveBoxDown()应该是不言自明的,但是将当前框(调用此函数)与它下面的框切换。

这就是发生的事情......

当仅执行项目列时,会正确添加并重新呈现具有默认项目的附加列。但是,当首先执行 moveBoxDown 时,框会正确切换并重新渲染,但是当我去执行 addItemColumn 时,子 Box 没有看到对 Box 的任何更新。

奇怪的是 1)addItemColumn()工作和渲染 2)moveBoxDown()工作和渲染

因此,更新 moveBoxDown 似乎不会导致问题出现在 addItemColumn 上。事实上,moveBoxDown()使用我的任何其他突变运行都非常有效。

3) Vue Devtools 显示 Box 已更新,因此box.items已更新 4) 根据示例代码<p>{{ box.items.length }}<p>更新父级而不是子级 Box。

如果它在父母身上不起作用,我可能会认为这对孩子来说是一个关键问题;但是,它确实并结合 devtools 正确显示了box孩子的更新,在我看来,出于某种未知原因,孩子没有检测到道具已更新?

我能想到解决这个问题的唯一方法是将 Box 变成一个开槽组件,因为父级知道,这似乎可以缓解这个问题。

我在 VueX 中有以下数据结构

Boxes = [
  {
    id: number
    items: [
      {
        id: number
        properties: {
          ...
        }
      },
      ...
    ]
  },
  ...
]

.push()在 VueX中正在添加一个项目,由addBox因此检测到更改触发。同样,一般来说这是可行的,但在某些情况下,即使 Vue 开发工具显示正确的、现已更新的 prop 值,它也会拒绝更新。

家长

<template>
  <b-button @click="addBox()">Add Box</b-button>

  <div v-for="(box, index) in boxes" :key="`box_${index}`">
    <!-- This updates so is not related to the parents loop -->
    <p>{{ box.items.length }}</p>
    <Box :box="box" />
  </div>
</template>

<script>
// Import VueX
import { mapGetters, mapActions } from "vuex";

// Import Components
import Box from "~/components/Box";

export default {
  name: "BoxesPage",
  layout: "BoxesLayout",
  components: { Box },
  computed: {
    ...mapGetters({
      boxes: "items/boxes"
    })
  },
  methods: {
    ...mapActions({
      addItemColumn: "items/addItemColumn"
    })
  },
  async fetch({ store, params }) {
    await store.dispatch("items/getInventory");
  }
};
</script>

盒子

<template>
  <div>
    <!-- Neither of these update either, so this is not related to the child's loop -->
    <p>{{ box }}<p>
    <p>{{ box.items.length }}<p>
    <b-button
      @click="moveBoxDown()"
      icon-right="chevron-down"
    />
    <div
      v-for="item in box.items"
      :key="
      `box_${box.index}_item_${item.index}_${item.name}`"
    >
      <!-- This does not add a new item -->
      <Item :item="item" />
    </div>
  </div>
</template>

<script>
// Import VueX
import { mapGetters, mapActions } from "vuex";

// Import Components
import Item from "~/components/Item";

export default {
  name: "Box",
  components: { Item },
  props: {
    Box: {
      type: Object,
      required: true
    }
  },
  methods: {
    ...mapActions({
      moveBoxDown: "items/moveBoxDown",
    })
  }
};
</script>

我不会附加 VueX 行,因为 VueX 实现似乎完全没问题……无论是正确地重新渲染还是 Vue 开发工具没有显示道具已正确更新。

编辑:VueX“items.js”

export const state = () => ({
  boxes: []
});

export const actions = {
  moveFrameDown({ commit }, frameIndex) {
    commit('switchBoxes', { fromIndex: frameIndex, toIndex: frameIndex + 1 });
  },
  addBoxColumn({ commit }, item) {
    // Item is a default item type
    commit('newItemColumn', item);
  },
}

export const mutations = {
  SwitchBoxes: (state, { fromIndex, toIndex }) => {
    state.boxes[fromIndex] = {
      index: fromIndex,
      items: state.boxes.splice(toIndex, 1, {
        index: toIndex,
        items: state.frames[fromIndex].items
      })[0].items
    };
  },
  newItemColumn: (state, itemProps) => {
    state.boxes[0].items.push({
      id: state.idCounter
      props: itemProps
    });
    state.idCounter += 1;
  }
};

标签: vue.jsnuxt.js

解决方案


你的例子不是很小,所以我只能猜测可能是什么原因。

这是一个危险信号:

state.boxes[fromIndex] = { ... }

文档

Vue 无法检测到数组的以下更改:

  1. 当您直接使用索引设置项目时,例如vm.items[indexOfItem] = newValue
  2. 当您修改数组的长度时,例如vm.items.length = newLength

您同时也在splice()对数组进行操作,Vue 可以检测到,所以巧合的是,数组更改可能会反映在视图中,但是您可能没有意识到您分配给数组索引的新对象不会是被动的。

您需要使用Vue.set()

Vue.set(state.boxes, fromIndex, { ... })

推荐阅读