vue3 watch 最佳实践

项目中在监听数据变化,有时候不生效,又去翻阅文档,watch 和 watchEffect 如何选择才比较好?

这些问题,都挺关键的,现在总结一下比较好的做法。

watch

watch 的第一个参数是监听的数据源,有四种形式:

  1. ref:refcomputed;
  2. reactive;
  3. getter: 返回一值的函数;
  4. 以上三种组成的数组

监听 ref 和 shallowRef

<script setup lang="ts">
  const a = ref(0)
  const b = ref(10)
  watch(a, (a, oldA) => {
    console.log(`watch(a),a:${a},oldA:${oldA}`)
  })
  // 监听不到 ❌ ts 也给出提示
  watch(a.value, (a, oldA) => {
    console.log(`watch(a),a:${a},oldA:${oldA}`)
  })

  watch([a, b], ([a, b]) => {
    console.log(`watch([a, b] ,a:${a},b:${b}`)
  })

  const sum = computed(() => {
    return a.value + b.value
  })

  watch(sum, sum => {
    console.log(`watch(sum) ,sum:${sum}`)
  })

  watch([a, () => b.value + 1000], ([a, sum]) => {
    console.log(`watch([a, () => b.value + 1000] a:${a} sum:${sum}`)
  })

  function changeA() {
    a.value += 1
    b.value += 10
  }

  const numList = shallowRef([1, 2, 3])

  function changeNumList() {
    // numList.value.push(10, 20, 30)  
    // NOTE shallowRef 的数组,使用 push pop 等方法修改 无法监测到 ❌
    numList.value = [...numList.value, 10, 20, 30]
  }

  watch(numList, numList => {
    console.log(numList, `watch(numList), numList: ${numList}`)
  })

  function changeNumList2() {
    numList.value = ['10', '20', '30']
  }
  const shallowA = shallowRef({
    a: {
      b: {
        c: 10,
      },
    },
    d: 100,
  })
  watch(shallowA, val => {
    console.log('watch(shallowA): ', val)
  })
  watch(
    () => shallowA.value.a,
    val => {
      console.log('watch(() => shallowA.value.a): ', val)
    }
  )

  function changeShallowA() {
    shallowA.value = {
      // @ts-ignore
      e: 1000,
    }
  }
</script>

<template>
  <div>
    <h2>watch ref</h2>
    <p>a:{
  { a }}</p>
    <p>b:{
  { b }}</p>
    <p>sum:{
  { sum }}</p>
    <button @click="changeA">changeA</button>
    <h2>watch shallowRef</h2>
    <p>shallowA:{
  { shallowA }}</p>
    <button @click="changeShallowA">changeShallowA</button>
    <h2>watch array</h2>
    <p>numList:{
  { numList }}</p>
    <button @click="changeNumList">changeNumList</button>
    <button @click="changeNumList2">changeNumList2</button>
  </div>
</template>

最佳实践

  1. 监听 ref: watch(ref) 或者 watch(computedRef)

  2. 监听 shallowRef:watch(ref) 或者 watch(computedRef)

  3. 关于 ref和 shallowRef 的修改,使用xxx.value = newValue,即直接重置,可有效降低心智负担。

比如上面的数组添加,numList 是一个 shallowRef ,使用数组方法 numList.value.push(10, 20, 30) 添加元素,无法监测到 numList 的改变 。使用 pushpop 等改变数组类型的 ref,是能监听到的。

修改数组,推荐都这样改:

numList.value = [...numList.value, 10, 20, 30] // 直接重置数组 shallowRef 也是如此

修改对象某个属性:

shallowA.value = {
   
  ...shallowA.value,
  a: {
   
    b: 'this is a.b '
  },
  // @ts-ignore
  e: 1000,
}

关于 reactive 和 shallowReactive 的监听

  • 监听整个 reactive,直接写,watch(person),不用添加 {deep: true},是默认深度监听的;
  • 使用函数返回整个 reactive:watch(()=>({..person})), 默认浅层监听的,监听深层属性,添加{deep:true}
  • 监听 reactive 的单个属性,使用函数返回,监听多个属性,使用数组:watch(person.age) watch([()=>person.age, ()=>person.name])

不能直接侦听响应式对象的属性值

const obj = reactive({
   
  count: 0
})

// 错误,因为 watch() 得到的参数是一个 number ❌
watch(obj.count, (count) => {
   
  console.log(`count is: ${
     count}`)
})
// 应该这样监听:提供一个 getter 函数 ✅
watch(
  () => obj.count,
  (count) => {
   
    console.log(`count is: ${
     count}`)
  }
)

shallowReactive 只是第一层属性是响应式的,添加 {deep:true} ,也监听不到深层次属性。

watch 的第三个参数

watch 的第三个参数,是一个配置对象

watch(reactiveVariable, effectCallback, {
   
  deep: true, // 监听深层属性
  imme
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值