【问题标题】:Vue prop not updating properly in a child componentVue 道具没有在子组件中正确更新
【发布时间】:2020-12-11 01:00:05
【问题描述】:

我有一个从父组件接收道具的子组件。我添加了一个事件来在单击按钮时更新父组件中的道具。但是子组件并没有检测到prop的变化。

大概代码:

父组件:

<template>
  <table>
    <Student v-for="(student, index) in students"
      :key="index"
      :student="student"
      :attendance="attendance[student.id]"
      @attended-clicked="changeAttendance"
    ></student>
  </table>
</template>

<script>
  export default {
    data() {
      return {
        students: [
          {id: 1, name: 'Pepito'},
          {id: 2, name: 'Sue'},
        ],
        attendance: {
          1: {attended: true},
          2: {attended: false},
        }
      }
    },
    methods: {
      changeAttendance(studentId) {
        this.attendance[studentId].attended = !this.attendance[studentId].attended;
      }
    }
  }
</script>

子组件:

<template>
  <tr>
    <td>{{ student.name }}</td>
    <td><v-btn :color="attendance.attended ? 'green' : 'red'"
          @click="$emit('attended-clicked', student.id)"
        >Attended</v-btn>
  </tr>
</template>

<script>
  export default {
    props: ['student', 'attendance']
  }
</script>

我已尝试使代码尽可能少,以便让您了解我想要实现的目标。期望是当按钮被点击时,attendance.attended 会发生变化。

我可以验证使用 Vue 开发人员工具单击时该值是否正在更改(尽管我必须按下“强制刷新”按钮才能看到更改)。但显然,孩子的观点并没有接受这种变化。

我在这里做错了什么会破坏反应性吗?

我也尝试过使用Vue.set 和一些类似这样的代码:

methods: {
  changeAttendance(studentId) {
    let attendance = this.attendance[studentId];
    attendance.attended = !attendance.attended;
    Vue.set(this.attendance, studentId, attendance);
  }
}

没有区别。

感谢您对我做错的任何见解,谢谢!

【问题讨论】:

  • 你能做一个sn-p
  • 不知道如何用多个 vue 组件制作 sn-p 和 vuetify。不过我会调查的
  • studentsattendance 我猜应该是一个数组
  • @Chris 这是你需要的吗:s8o8q.csb.app?
  • 这是sandbox

标签: javascript vue.js vue-component vue-reactivity vue-props


【解决方案1】:

根据 cmets,根本问题是 attendance 被设置为 {},这意味着根据 change detection part in the VueJS docsattendance[student.id] 对象实际上并不存在或不再被跟踪。这就是问题中提供的Vue.set 示例代码应该做的事情。

基本上我看到了两种解决方法:

  1. 将出勤设置为在 API 返回结果时始终使所有学生 ID 可用,从而使对象始终具有已经工作的对象
  2. 当您需要从 attendance 获取值时开始跟踪反应性。

由于我不知道 API 以及它是如何被调用的,我将为选项 2 提供答案。提供的代码几乎可以工作,它只需要对 Parent 组件进行两次更改,以确保学生考勤对象总是被填满,将来会被跟踪:

<template>
  <table>
    <!-- :attendance needs an object to work -->
    <Student
      v-for="(student, index) in students"
      :key="index"
      :student="student"
      :attendance="attendance[student.id] || {}"
      @attended-clicked="changeAttendance"
    />
  </table>
</template>

<script>
import Vue from "vue";
import StudentVue from "./Student.vue";

export default {
  data() {
    return {
      students: [{ id: 1, name: "Pepito" }, { id: 2, name: "Sue" }],
      attendance: {}
    };
  },
  methods: {
    changeAttendance(studentId) {
      // make sure to have an object when accessing a student!
      let attendance = this.attendance[studentId] || {};
      attendance.attended = !attendance.attended;
      // start tracking - this will always "reset" the tracking though!
      Vue.set(this.attendance, studentId, attendance);
    }
  },
  components: { Student: StudentVue }
};
</script>

由于this.attendance[student.id] || {} 被多次使用,我将其封装到getAttendance(studentId) {...} 函数中。在那里,Vue.set 可用于在对象之前不存在的情况下开始跟踪,从而使changeAttendance 更简单一些,|| {} 的意图更明确。

<template>
  <table>
    <Student
      v-for="(student, index) in students"
      :key="index"
      :student="student"
      :attendance="getAttendance(student.id)"
      @attended-clicked="changeAttendance"
    />
  </table>
</template>

<script>
import Vue from "vue";
import StudentVue from "./Student.vue";

export default {
  data() {
    return {
      students: [{ id: 1, name: "Pepito" }, { id: 2, name: "Sue" }],
      attendance: {}
    };
  },
  methods: {
    changeAttendance(studentId) {
      let attendance = this.getAttendance(studentId);
      attendance.attended = !attendance.attended;
    },
    getAttendance(studentId) {
      const studentAttendance = this.attendance[studentId];
      if (!studentAttendance) {
        Vue.set(this.attendance, studentId, { attended: false });
      }
      return this.attendance[studentId];
    }
  },
  components: { Student: StudentVue }
};
</script>

如果代码库在其他组件中使用this.something[something]this.getAttendance 可能看起来有点不一致。在这种情况下,最好先将 API 调用的结果更改给所有学生,然后再将其提供给Parent 组件。就个人而言,我会尝试使用该选项。我会使用this.$set 而不是Vue.set 来摆脱import Vue 线... ;)

【讨论】:

    猜你喜欢
    • 2020-09-30
    • 2018-12-30
    • 2020-01-07
    • 2020-08-07
    • 2021-08-09
    • 1970-01-01
    • 2020-01-19
    • 2018-01-15
    • 2021-12-23
    相关资源
    最近更新 更多