Vue3中watch无法监听的问题

2,508 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情

问题抛出

watch 函数用来侦听特定的数据源,并在回调函数中执行副作用

  • watch有三个参数:

参数1:监听的参数

参数2:监听的回调函数

参数3:监听的配置(immediate)

在Vue3中,在一些情况下,watch监听失效

<script setup lang="ts">
import { watch, ref } from 'vue'
const obj = ref({
  eat: '西瓜',
})
watch(obj, (newValue) => {
  console.log(newValue)
})
</script>

<template>
  <p>{{ obj.eat }}</p>
  <button @click="obj.eat = '面条'"><code>obj.eat = '面条'</code></button>
</template>

问题解决

解决 1:修改第 1 层

因为 watch 对 ref 数据的监听默认是浅监听的,既然是浅监听,那可以直接修改第一层就好啦,也就是 obj.value

<template>
  <button @click="obj = { eat: '面条' }"><code>obj = { eat: '面条' }</code></button>
</template>

解决 2:开启深度监听

<script setup lang="ts">
import { watch, ref } from 'vue'
const obj = ref({
  eat: '西瓜',
})
watch(
  obj,
  (newValue) => {
    console.log(newValue) // Proxy { eat: '面条' }
  },
  // #2
  { deep: true }
)
</script>

<template>
  <p>{{ obj.eat }}</p>
  <!-- #1 -->
  <button @click="obj.eat = '面条'"><code>obj.eat = '面条'</code></button>
</template>

解决 3:监听 reactive

obj.value 是一个 reactive 数据,而 reactive 数据是开启深度监听的,并且不能修改。

<script setup lang="ts">
import { watch, ref } from 'vue'
const obj = ref({
  eat: '西瓜',
})
watch(obj.value, (newValue) => {
  console.log(newValue) // Proxy { eat: '面条' }
})
</script>

<template>
  <p>{{ obj.eat }}</p>
  <button @click="obj.eat = '面条'"><code>修改 obj.eat</code></button>
</template>

🤔 注意:直接监听 reactive,对 reactive 本身的修改是不会触发监听的。

<button @click="obj = { eat: '面条' }"><code>obj = { eat: '面条' }</code></button>

解决 4:watch 指定函数,返回 ref

任何情况都不会触发监听,除非开启 deep。

<script setup lang="ts">
import { watch, ref } from 'vue'
const obj = ref({
  eat: '西瓜',
})
watch(
  () => obj,
  (newValue) => {
    console.log(newValue)
  }
)
</script>

<template>
  <p>{{ obj.eat }}</p>
  <button @click="obj.eat = '面条'"><code>obj.eat = '面条'</code></button>
  <button @click="obj = { eat: '面条' }"><code>obj = { eat: '馒头' }</code></button>
</template>

解决 5:watch 指定函数,返回 reactive(ref 中的对象)

对这个 reactive 本身的修改会触发监听,内部数据的变化则不会。开启 deep 后上面 2 种情况都会被触发监听。

<script setup lang="ts">
import { watch, ref } from 'vue'
const obj = ref({
  eat: '西瓜',
})
watch(
  () => obj.value,
  (newValue) => {
    console.log(newValue)
  }
)
</script>

<template>
  <p>{{ obj.eat }}</p>
  <button @click="obj.eat = '面条'"><code>obj.eat = '面条'</code></button>
  <button @click="obj = { eat: '馒头' }"><code>obj = { eat: '馒头' }</code></button>
</template>

解决 6:watch 指定函数,返回 reactive(直接定义的对象)

对这个 reactive 本身的修改和内部数据的变化都不会触发监听。开启 deep 后第 2 种情况会被触发监听。

解决 7:watch 指定函数,返回普通值

任何影响到此值的修改并且是响应式的,都会触发监听。

<script setup lang="ts">
import { watch, ref } from 'vue'
const obj = ref({
  eat: '西瓜',
})
watch(
  () => obj.value.eat,
  (newValue) => {
    console.log(newValue)
  }
)
</script>

<template>
  <p>{{ obj.eat }}</p>
  <button @click="obj.eat = '面条'"><code>obj.eat = '面条'</code></button>
  <button @click="obj = { eat: '馒头' }"><code>obj = { eat: '馒头' }</code></button>
</template>

今天就先写到这里了!!撒由那拉

image.png