Skip to content

注意

1 监听源什么时候使用函数

通常监听源是一个ref、一个响应式对象,此时不需要使用函数,如果要监听响应式对象的某个属性就需要使用 getter 函数,如:

js
const obj = reactive({ count: 0 })

// 这不起作用,因为此时监听源是一个值,是不变的
watch(obj.count, (count) => {
  console.log(`count is: ${count}`)
})

应该

js
// 提供一个 getter 函数,只有当 obj 对象的 count 属性发送变化时才触发监听
watch(
  () => obj.count,
  (count) => {
    console.log(`count is: ${count}`)
  }
)

2 什么时候使用 deep

如果监听源是引用类型(如ref(数组)ref(对象)reactive)或返回值为引用类型的 getter 函数,当需要强制深度遍历,以便在深层级变更时触发回调,就需要设置 deep 为 true,且变化前后,监听源值相同

如果不设置 deep 为 true,只有当监听源被整体赋值或替换时才触发回调函数,val1、val2 为变化后和变化前的值,且不一样。

2.1 ref(数组)

js
const users = ref([])
watch(users, (val1, val2) => {
  console.log(val1, val2)
})

// 不触发监听回调
function handleAdd() {
  users.value.push({ name: `name${Math.random()}`, age: 20 })
}
js
const users = ref([])
watch(users, (val1, val2) => {
  console.log(val1, val2)
}, { deep: true })

// 触发监听回调,val1、val2 相同
function handleAdd() {
  users.value.push({ name: `name${Math.random()}`, age: 20 })
}
js
const users = ref([])
watch(users, (val1, val2) => {
  console.log(val1, val2)
})

// 触发监听回调,val1、val2 不同,打印[{ name: 'Jack', age: 18 }] 和 []
function test() {
  users.value = [{ name: 'Jack', age: 18 }]
}

2.2 ref(对象)

下面是监听源为一个 ref(对象) 的例子:

js
const user = ref({ name: 'Jack' })
watch(user, (val1, val2) => {
  console.log(val1, val2)
}, { deep: true })

// 仅当设置了 deep 为 true,触发监听回调,val1、val2 相同,否则不触发
function test1() {
  user.value.name = 'Marry'
}

// 触发监听回调,val1、val2 不同,打印 {name: 'Marry'} 和 {name: 'Jack'}
function test1() {
  user.value = { name: 'Marry' }
}

2.3 reactive

注意如果监听源是 reactive,会隐式地创建一个深层侦听器,因此无需再显式设置 deep 为 true。

js
let user = reactive({ name: 'Jack' })
watch(user, (val1, val2) => {
  console.log(val1, val2)
}, { deep: true })

// 不管是否设置deep,都会触发监听回调,且 val1、val2 相同
function test1() {
  user.name = 'Marry'
}
// 直接给 reactive 赋值,这种做法是不对的。不会触发监听回调
function test2() {
  user = { name: 'Marry' }
}

2.4 返回值为引用类型的 getter 函数

js
const user = reactive({
  info: {
    name: 'Jack'
  }
})
watch(() => user.info, (val1, val2) => {
  console.log(val1, val2)
}, { deep: true })

// 仅当设置了 deep 为 true,触发监听回调,val1、val2 相同,否则不触发
function test1() {
  user.info.name = 'Marry'
}
// 触发监听回调,val1、val2 不同,打印 {name: 'Marry'} 和 {name: 'Jack'}
function test2() {
  user.info = { name: 'Marry' }
}

因为 reactive 会递归创建响应式对象,因此 user.info 也是响应式对象,所以下面写法更便捷。

js
const user = reactive({
  info: {
    name: 'Jack'
  }
})
watch(user.info, (val1, val2) => {
  console.log(val1, val2)
})

// 不管是否设置deep,都会触发监听回调,且 val1、val2 相同
function test1() {
  user.info.name = 'Marry'
}
// 相当于直接给 reactive 赋值,这种做法是不对的。不会触发监听回调
function test2() {
  user.info = { name: 'Marry' }
}