【问题标题】:Vue Child Component Doesn't Update on Prop ChangeVue 子组件不会在道具更改时更新
【发布时间】:2020-01-19 20:09:46
【问题描述】:

我正在更新发送到 Vue 中的“锻炼”组件的“锻炼”道具。在子组件中,我发出一个函数来增加你所在的集合。该函数在父组件中触发(我得到了 console.logs()),但子组件没有重新渲染。

家长:

<ExerciseListItem
  v-for="(exercise) in exercises"
  v-on:completeSet="completeSet"
  v-on:selectExercise="selectExercise"
  v-bind:exercise.sync="exercise"
  v-bind:isActiveExercise="exercise.slug === activeExerciseSlug"
  v-bind:key="exercise.slug"
/>

方法:

methods: {
  completeSet: function(slug) {
    console.log("complete-set", slug);
    const exercise = this.getExerciseBySlug(slug);
    exercise.completedSets++;
    if (exercise.completedSets === exercise.totalSets) {
      this.completeExercise(slug);
    }
  },
  completeExercise: function(slug) {
    this.getExerciseBySlug(slug).isComplete = true;
    console.log("COMPLETE-exercise", slug);
  },
  getExerciseBySlug: function(slug) {
    return this.exercises.find(exercise => exercise.slug === slug);
  },
  selectExercise: function(selectedSlug) {
    this.activeExerciseSlug = selectedSlug;
  }
},

子模板

<li
  v-bind:class="{ 'white-box': true, complete: exercise.isComplete }"
  v-on:click="exercise.totalSets > 1 ? $emit('selectExercise', exercise.slug) : $emit('completeSet', exercise.slug)"
>

Here's the project on Github

And a live demo

帮助感谢????

【问题讨论】:

  • exercise.completedSets 的值应按预期更新并触发重新渲染。如果 'exercie' 对象本身没有反应(其属性没有 setter/getter),什么可以防止这种情况发生。在您的代码中,不清楚练习对象的来源 - 您能解释或发布代码吗?
  • 您应该为您的演示启用 Vue 开发工具。这将有助于我们调试。
  • 嘿@TimWickstrom,完全不知道那是一回事。我现在加了????
  • @MarcRo 原始数据作为道具传递给路由。原始数据在default.js中
  • @RossWhitehouse 我明白了,我之前没有时间检查回购。问题是您的道具(数组)中的嵌套对象不是反应性的。默认情况下,Vue 不会使嵌套属性具有反应性——因此它无法检测到它们的值何时发生变化。您可以做两件事:1. 明确地使您的道具反应或 2. 手动强制更新。

标签: javascript vue.js data-binding components vue-props


【解决方案1】:

组件没有更新,因为您的 prop 的嵌套值不是响应式的,因此,vue 不会注意到它们正在更改。

如何在 Vue 中使嵌套属性具有响应性

以下内容适用于您的 vue 应用中的所有状态 - 无论它位于 vuex 商店、您的 data() 选项中还是位于 prop 中。

默认情况下,vue 仅在声明状态时才使状态反应。这意味着动态(在运行时)分配的状态不是响应式的(例如,mounted() { this.bar = 'two' } 不会在您的data() 中创建响应式属性bar)。

如果你想动态创建反应状态,你需要遵循两条规则:

  1. 所有属性都需要设置为Vue.set(rootObject, key, value)(例如mounted() { this.$set(this, 'bar', 'two') } - this.$set()Vue.set() 的别名)。在这里阅读:Vue Doku

  2. 数组需要填充原生数组属性(Array.prototype.push() 等)。按索引设置数组元素不会使这些元素反应。 注意: Vue.set(rootArray, 1, value) 也不起作用 - 因为它通过索引设置元素。在此处阅读更多信息:Vue Gotchas

【讨论】:

  • 感谢@MarcRo 回复我。我已经在这里实施了修复。幸运的是,练习道具是一个对象,所以我所要做的就是更改函数以便它使用 this.$set: ``` completeSet: function(slug) { const exercise = this.getExerciseBySlug(slug); this.$set(exercise, "completedSets", exercise.completedSets + 1); if (exercise.completedSets === exercise.totalSets) { this.completeExercise(slug); } }, ``` 但它仍然没有更新,但 vue devtools 显示了道具。我已经推送了更改,但我没有在标题旁边输出完成的集。
  • 对不起,里面有一些错误的代码,这是我现在得到的:``` completeSet: function(slug) { const exercise = this.getExerciseBySlug(slug);常量练习索引 = this.exercises.indexOf(练习); const newExercise = { ...this.exercises[exerciseIndex], completedSets: this.exercises[exerciseIndex].completedSets + 1 }; this.$set(this.exercises, exerciseIndex, newExercise); this.$forceUpdate(); }, ``` 哪个有效,但这取决于 forceupdate,我宁愿不使用它
【解决方案2】:

如果需要,您可以在发出后在父组件中调用 this.$forceUpdate(),这将强制重新渲染。

不确定为什么您的子组件没有自动触发更新的根本问题。

【讨论】:

    猜你喜欢
    • 2018-08-09
    • 2020-06-17
    • 2021-10-03
    • 2019-03-03
    • 2019-11-26
    • 1970-01-01
    • 2021-02-25
    • 2018-12-30
    • 1970-01-01
    相关资源
    最近更新 更多