vue子组件无法根据prop属性值变化实现视图更新问题记录

问题描述

在vue中,有一个父组件和一个子组件,在父组件里有一个变量,在这个变量里有一个属性值和一个回调函数,并且这个变量是通过computed直接return的,如下:

computed: {
    
    
	testObj() {
    
    
		return {
    
    
			name: '空标题',
			cb(option) {
    
    
				option.name = '标题更改了'
			}
		}
	}
}

在这个父组件中调用子组件并通过prop的形式将这个对象传递给子组件,如下:

<testChild :testObj="testObj" />

testChild 这个子组件中,展示这个变量的name值,并有一个事件会触发这个变量的回调函数,更改这个name值,如下:

<template>
	<p>{
    
    {
    
    testObj.name}}</p>
	<button @click="updateTest">更新</button>
</template>
export default {
    
    
	name: 'TestChild',
	props:{
    
    
		testObj: {
    
    
			type: Object,
			default: ()=>({
    
    })
		}
	},
	mathods: {
    
    
		updateTest() {
    
    
			this.testObj.cb(this.testObj)
			console.log(this.testObj)
		}
	}
}

现在的问题是,在子组件触发更新事件后,通过console打印可以看到testObj中的name值已经发生了改变,但是视图并没有更新

原因分析

子组件视图之所以没有根据响应式实现更新跟computed的实现原理有关,在vue中,可以通过datacomputedpropwatch的方式为当前实例中的变量添加上响应式(vue2通过defineProperty方法,vue3通过proxy,实现原理这里不赘述)。但是他们之间的实现方式有所不同,在vue源码中computed是计算属性,也就意味着,computed首先是监听参与计算变量变化,进而通知watcher进行派发更新。如果参与计算的变量没有变化,而主动更改 computed 中的变量或者变量里的属性值,只能触发computedsetter方法(前提computed是通过getset设置的)。而在本示例下,父组件是返回一个完整的testObj对象,在父组件中没有任何变量参与其中计算,这就使得我们在更改testObj的属性值时,父组件认为这个testObj并没有更新不需要触发watcher进行派发更新。因此无论是在子组件还在在父组件,通过testObj.name 展示的值都无法进行更新。

解决方案

解决这个问题的方法可以有多种
一,可以把这个变量放到data中而不是computed

data() {
    
    
	return {
    
    
		testObj: {
    
    
			name: '空标题',
			cb(option) {
    
    
				option.name = '标题更改了'
			}
		}
	}
}

二、在计算属性中使用变量,通过更改这个变量实现computed更新

data() {
    
    
	return {
    
    
		isChange: false
	}
}
computed: {
    
    
	testObj() {
    
    
		return {
    
    
			name: isChange ? '标题更改了' : '空标题' ,
			cb(option) {
    
    
				this.isChange  = true
			}
		}
	}
}

三、在子组件中通过变量赋值的方法,将该变量重新加上响应式
因为在vue中只要在data()中定义变量,vue就会自动为其添加响应式

<template>
	<p>{
    
    {
    
    testObj_ .name}}</p>
	<button @click="updateTest">更新</button>
</template>
props:[
	testObj: {
    
    
			type: Object,
			default: ()=>({
    
    })
		}
],
data() {
    
    
	return {
    
    
		testObj_: {
    
    }
	}
},
created() {
    
    
this.testObj_ = this.testObj
}

以上就是相关的优化方案。

猜你喜欢

转载自blog.csdn.net/My_Soul_/article/details/129622840