vue2和vue3中父级属性改变,子组件props属性未改变,且不能触发监听的问题解决及响应式原理分析

1|0场景:

  • 调用自定义组件的时候,父级传给子组件的值可能是异步的,然后这也分两种情况
    • 子组件的值只需要在初始化时获取,之后就不变了
    • 子组件的值还会变化,在后面的操作中有异步请求,跟随父级拿到的数据变化
  • 这时会有父级已经请求拿到数据了,但是子组件的值还没变,也没有触发回显,界面没有改变

2|0解决:

2|1vue2

  • 虽然都是响应式的问题,但是解决思路可以不一样,但其实也可以一样
  • 总体来说有几种解决方法:
    • 用v-if控制组件在拿到数据之后再渲染,这很明显只能解决第一种情况,不适用于第二种,但是其实这个方法并不是从本质解决问题,而是投机取巧,但是还是记录一下吧:
    <mycomp :data="data" v-if="is_data_got"></mycomp>
    mounted () { const that = this // getData 是封装好的接口调用 getData().then(res => { that.data= res.data that.is_data_got = true }) }
    • 网上很多博客说在子组件内用watch监听父级传过来的props,具体实现就不说了,比较简单。而且主要是因为这个方案也不是问题的根本,它甚至在我遇到的情况中并不管用,具有局限性。我遇到的这种情况的本质是父级在改变变量值的时候,并不是响应式的,所以不能触发子组件一起变化,甚至不能触发子组件的监听函数,尝试后发现,监听函数根本进不去。
    • 本质:触发响应式
      • vue响应式原理官方文档,强烈建议看一看
      • 这里看下文档里的监测变化的注意事项这里,有几种特殊情况是非响应式的
      • 对于对象变量,如果在声明时有指明的默认属性名,那么这些属性的变化是响应式的,但是如果是没有声明的额外属性,就是非响应式,官方例子:
        var vm = new Vue({ data:{ a:1 } }) // `vm.a` 是响应式的 vm.b = 2 // `vm.b` 是非响应式的
      • 对于数组,如果是用索引修改了数组的某一项,或修改数组长度,都是非响应式的,看官方例子:
        var vm = new Vue({ data: { items: ['a', 'b', 'c'] } }) vm.items[1] = 'x' // 不是响应性的 vm.items.length = 2 // 不是响应性的
      • 我就是这种情况,而且对象和数据我都遇到了,解决办法:
      • 对象型,可以在声明时直接初始化默认属性值,防止额外属性的出现。或者麻烦一点,重新对整个对象赋值
      • 数组型,可以用Array.splice方法来替换指定位置的值,不用索引,如arr.splice(index, 1, newValue)
      • 对象型和数组型,都可以用this.$set(item, index/property, val)来强制响应,如:
        const obj = {} const arr = [1, 2] this.$set(obj, "name", "小明") // 这时obj.name = "小明" 就是响应式 this.$set(arr, 1, 3) // 这时arr[1] = 3 就是响应式

2|2vue3

  • vue3的组件是没有this的,所以很多this相关的用法都是改了的,其中this.$set是被摒弃的
  • vue3中用ref和reactive做响应式声明,这两个属性的用法算是vue3的基础,需要熟练掌握
    • ref一般用于基本类型声明
      • 除了string, number, boolean等类型,也可以是对应的[],如 const var1 = ref<string[]>([])
      • ref在js/ts中引用和修改的时候,都需要取value属性才行,如 var1.value.push('一个值'),这样才能正确响应
      • ref在template中引用则不需要取value属性,直接用就行,如 <div v-for="item in var1">{{ item }}</div>
      • 除了声明响应式变量以外,ref还用于同vue2一样对HTMLElement的标记<div ref="test">标记</div>,在vue2中调用ref标记的dom是用this.$refs.test,而如果是子组件,调用子组件的方法也可以直接this.$refs.test.func(),这一点上个人感觉还是vue2方便,在vue3,获取标记的dom比较简单,直接声明一个标记名相同的变量就行,如const test = ref(),这样就已经拿到test标记的div了,而如果要调用子组件的方法,则还需要在子组件中暴露给外部调用的方法,非setup写法就是export里面导出,而setup写法则是defineExpose({ func })
    • reactive一般用于对象类型声明
      • const obj = reactive({ name: '对象' }),在js/ts和template中都直接用其对应属性
  • 好啦,总结就是,只要变量变化时是响应式的,子组件就能一起变化,所以出现子组件不响应的情况时,首先看看父级的变量是不是响应式的

__EOF__

本文作者Mizuki
本文链接https://www.cnblogs.com/mizuki-vone/p/16442726.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Mizuki-Vone  阅读(8261)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示