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

原创文章,作者:,如若转载,请注明出处:https://blog.ytso.com/273334.html

(0)
上一篇 2022年7月10日
下一篇 2022年7月10日

相关推荐

发表回复

登录后才能评论