vue3使用watch监听store简单状态管理中reactive对象

参考:
Vue3中watch监视reactive定义数据的“坑” - csdn
watch - Vue.js
vue中watch的使用写法 - csdn
【Vue】watch的详细⽤法 - csdn
vue中watch的用法 - 博客园

前言

在项目中,我想用store来全局管理document.body.clientWidth
然而却发现watch无法监听store中的clientWidth

测试复现

我定义的store是这样的:

const store = {
debug: true,
// 使用一个 reactive 方法让对象作为响应式对象。
bodyWidth: reactive({
value: 0,
}),
setBodyWidthAction(newVal) {
if (this.debug) {
console.log('setBodyWidthAction triggered with', newVal)
}
this.bodyWidth.value = newVal
},
}

加一个按钮去测试:

<el-button @click="testWatch">testWatch</el-button>
data() {
return {
sharedBodyWidth: this.$store.bodyWidth,
}
},
methods: {
testWatch() {
this.$store.setBodyWidthAction(Math.random())
console.log(this.sharedBodyWidth)
},
},
watch: {
sharedBodyWidth: {
handler(newVal) {
console.log(`watch sharedBodyWidth=${newVal.value}`)
},
immediate: true,
},
},

发现了如下打印:
image.png

显然我们的set方法执行了,data里的变量也跟随响应式变量bodyWidth改变了
但却没有被watch监听到。

面向百度编程

面向百度编程了半小时,给watch加上了deep参数

普通的watch方法无法监听到对象内部属性的改变,需要deep属性对象进行深度监听。

watch: {
sharedBodyWidth: {
handler(newVal) {
console.log(`watch sharedBodyWidth=${newVal.value}`)
},
immediate: true,
deep: true,
},
},

这下可以了:
image.png

扩展

还有另外一种方式也可以实现,直接监听reactive变量的一个属性:

watch: {
'sharedBodyWidth.value': {
handler(newVal) {
console.log(`watch sharedBodyWidth=${newVal}`)
},
immediate: true,
},
},

image.png

在我们监听reactive定义的对象时,默认强制开启deep,这也是监听sharedBodyWidth.value生效的原因。此外oldValue无法监听到。

如果我们要监听reactive对象定义的对象属性的子属性,需手动配置deep: true。同样的,oldValue无法监听到。

此外,immediate表示在watch中首次绑定得时候,是否执行handler。默认是false

watch的写法

关于watch的写法,大概有4种:

watch: {
// 1: a可以是data,也可以是computed
a(newVal, oldVal) {},
// 2:
a: {
handler(newVal,oldVal){},
immediate:false,
deep:false,
},
// 3:
'a.v': {
handler(newVal,oldVal){},
immediate:false,
deep:false,
},
// 4: 监听store中的状态
'$store.a.value': {
handler(newVal,oldVal){},
}
}

使用store的状态做双向数据绑定

const store = {
inputVal: reactive({
value: "inputVal is a string"
}),
setInputValAction(newValue) {
this.inputVal.value = newValue
},
}
<el-input v-model="inputVal"></el-input>
// ...
computed: {
inputVal: {
get() { // 使用箭头函数this是undefined
return this.$store.inputVal.value
},
set(val) {
this.$store.setInputValAction(val)
},
}
},
watch: {
"$store.inputVal.value": {
handler(newVal) {
console.log(`watch $store.inputVal.value=${newVal}`)
},
immediate: true,
},
inputVal(newVal) {
console.log(`watch inputVal=${newVal}`)
},
},

image.png

image.png

posted @   云白Li  阅读(6327)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示