[Vue] 父组件明明按照正确的绑定方式更新了传递给子组件的prop属性 子组件却没有及时更新。解决方案:key值 nextTick watch监听。

prop介绍

prop是单向数据流,父组件传递给子组件的数据发生改变,而子组件的页面中引用了该prop,那么按理说子组件会重新渲染,将最新的prop渲染到页面上。

能正常更新的案例

在父组件中启动定时器,每隔1s对状态数据parentNum进行加一操作。父组件中引用子组件时将parentNum作为属性传入。

下面的例子实现的效果是子组件每隔一秒都会更新。从0开始每隔一秒加1并更新在页面上。
请添加图片描述

<!--父组件-->

<template>
  <div class="parentContainer">
      我是父组件
      <child ref="mychild" :num="parentNum"></child>
  </div>
</template>

<script>
import Child from './Child.vue'
export default {
  data () {
    return {
      parentNum: 0
    }
  },
  components: {
    Child
  },
  mounted () {
    this.changeData()
  },
  methods: {
    changeData () {
      const _this = this
      setInterval(function () {
        _this.parentNum = _this.parentNum + 1
      }, 1000)
    }
  }
}
</script>

<style scoped>
.parentContainer {
    width: 500px;
    height: 500px;
    background-color: gray;
}
</style>
<!--子组件-->

<template>
  <div class="childContainer">
      我是子组件
      <div class="inner" ref="inner">{{num}}</div> <!--在模板中使用num-->
  </div>
</template>

<script>
export default {
  props: {
    num: Number
  },
}
</script>

<style scoped>
.childContainer {
    width: 200px;
    height: 200px;
    background-color: green;
    font-size: 30px;
    margin: auto;
}
.inner {
    color: red;
}
</style>

不能更新的按钮

如果我们在子组件的模板中没有使用到prop变量,而只是在子组件的方法中使用了prop变量,那么根据vue的绑定原理来说是不会触发重绘的。所以子组件中即使获取到更改后的prop但是组件不会进行重新渲染。

参考下面的例子:下面的例子是子组件中永远显示0。通过调试工具我们发现,子组件的num一直在进行自加操作,但是没有更新页面。

<!--父组件-->

<template>
  <div class="parentContainer">
      我是父组件
      <child ref="mychild" :num="parentNum"></child>
  </div>
</template>

<script>
import Child from './Child.vue'
export default {
  data () {
    return {
      parentNum: 0
    }
  },
  components: {
    Child
  },
  mounted () {
    this.changeData()
  },
  methods: {
    changeData () {
      const _this = this
      setInterval(function () {
        _this.parentNum = _this.parentNum + 1
      }, 1000)
    }
  }
}
</script>

<style scoped>
.parentContainer {
    width: 500px;
    height: 500px;
    background-color: gray;
}
</style>
<!--子组件-->

<template>
  <div class="childContainer">
      我是子组件
      <div class="inner" ref="inner"></div>
  </div>
</template>

<script>
export default {
  props: {
    num: Number
  },
  mounted () {
    this.init()
  },
  methods: {
    init () {
      this.$refs.inner.innerHTML = this.num // 在此处使用了prop 在模板中没有使用prop
      // 通过上面的语句去更新页面
    }
  }
}
</script>

<style scoped>
.childContainer {
    width: 200px;
    height: 200px;
    background-color: green;
    font-size: 30px;
    margin: auto;
}
.inner {
    color: red;
}
</style>

解决方案

通过分析上面的代码,我们发现页面不更新的根本原因是因为子组件的init方法没有被调用。所以有以下三种解决方案。

第一种方案是在子组件中监听prop的变化然后去调用方法

// 子组件

export default {
  props: {
    num: Number
  },
  mounted () {
    this.init()
  },
  watch: {
    num (val) { // 关键
      this.init() // 调用init
    }
  },
  methods: {
    init () {
      this.$refs.inner.innerHTML = this.num
    }
  }
}

第二种方案是通过nextTick结合ref在父组件中调用子组件的方法。nextTick的作用是在在下次 DOM 更新循环结束之后执行延迟回调。

// 父组件

export default {
  data () {
    return {
      parentNum: 0
    }
  },
  components: {
    Child
  },
  mounted () {
    this.changeData()
  },
  methods: {
    changeData () {
      const _this = this
      setInterval(function () {
        console.log(1)
        _this.parentNum = _this.parentNum + 1
        _this.$nextTick(() => {
          _this.$refs.mychild.init() // 调用
        })
      }, 1000)
    }
  }
}

第三种方案是在使用子组件时添加key属性

<!--父组件-->

<template>
  <div class="parentContainer">
      我是父组件
      <child :num="parentNum" ref="mychild" :key="new Date().getTime()"></child>
  </div>
</template>

参考

《Vue父组件修改了通过 props传递给子组件的数据,子组件没有及时更新》

Vue 3 中,组件传递给子组件的参数发生改变时,组件应该及时更新。如果组件没有及时更新,可能是由于以下几个原因: 1. 使用了不可变对象:Vue 3 在进行响应式更新时,会对比新旧是否相等。如果你使用了不可变对象(如使用 `Object.freeze` 冻结了对象),Vue 3 将无法检测到对象的变化,导致组件更新。确保传递的参数是可变的对象。 2. 使用了 `v-if` 条件渲染:如果你使用了 `v-if` 条件渲染来控制组件的显示和隐藏,当组件传递的参数发生改变时,组件可能无法及时更新。这是因为 Vue 3 在条件渲染时会缓存之前的组件实例,而不是销毁和重新创建。你可以尝试使用 `v-show` 或者给子组件添加一个唯一的 `key` 来解决这个问题。 3. 直接修改了数组或对象的元素:Vue 3 在进行响应式更新时,只会对已经被访问过的属性进行追踪。如果你直接修改了数组或对象的元素,而不是通过 Vue 提供的方法(如 `push`、`pop`、`splice` 等)进行修改Vue 3 将无法检测到这些变化,导致组件更新。请确保使用 Vue 提供的方法来修改数组或对象。 如果以上的解决方案没有解决你的问题,你可以检查一下是否有其他因素导致组件更新,比如在组件中是否正确传递了参数,或者组件是否正确地接收了参数。你也可以提供一些代码片段,以便更好地帮助你解决问题。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值