【问题标题】:Vue child component props not updatingVue子组件道具没有更新
【发布时间】:2020-09-30 11:16:29
【问题描述】:

在所有其他问题中,我发现数据被用于阻止反应。这里没有使用数据,prop 本身在渲染中更新失败。

我的 VueX 函数是:

addItemColumn() 在第一个 Box 中创建一个新列,本质上是不允许 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> 更新父框而不是子框。

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

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

我在 VueX 中有如下数据结构

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

在 VueX 中使用 .push() 添加项目,由 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 开发工具没有显示 prop 已正确更新。

编辑: 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;
  }
};

【问题讨论】:

  • 什么具体不更新?当您添加一个盒子(数组的问题)时,附加的盒子不会显示在屏幕上,还是现有盒子的属性没有更新(盒子对象的问题)? 99% 的视图没有更新是由于没有预先正确声明反应数据,或者以 Vue 无法检测到的方式改变数组/对象,但是由于您省略了该代码,因此很难查明确切的问题。
  • 是的,很抱歉,澄清一下当一个新的盒子被添加时它不会更新。我看看是否可以添加 VueX 代码或制作 JSFiddle。显示所有产生错误的代码有点复杂,因为它有点极端。
  • @DecadeMoon 我添加了 VueX 函数的示例,并阐明了特定的边缘情况以及应该发生的事情以及进一步发生的事情。我不确定看到 VueX 是否会特别有帮助,因为正如我一直提到的 DevTools 和 Parent 一样,box 在更新后的状态被正确表示和渲染。据我所知,这似乎是一个奇怪的问题,因为道具没有触发父母和孩子 Box 之间的更新。

标签: vue.js nuxt.js


【解决方案1】:

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

这是一个危险信号:

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

来自docs

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

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

你同时也在数组上做一个splice(),Vue可以检测到,所以巧合的是,数组的变化可能会反映在视图中,但是你可能没有意识到你分配的新对象到数组索引不会反应。

你需要使用Vue.set():

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

【讨论】:

  • 非常感谢!就是这个小细节,第一次使用 Vue/VueX,似乎我太自大了,认为我做的一切都很完美,过于关注调试(确认偏差。)我确实觉得奇怪的是 Vue Devtools 显示数据更新虽然在孩子,也许开发工具不能保证这一点,或者这是 Vue 中的一个奇怪案例。不管怎样,我现在已经在 Vue 中学到了教训——总是仔细检查——非常感谢!
猜你喜欢
  • 2020-12-11
  • 2018-12-30
  • 2020-08-07
  • 1970-01-01
  • 2021-08-09
  • 2019-11-12
  • 2020-01-19
  • 1970-01-01
  • 2018-11-25
相关资源
最近更新 更多