Vue3中watch和watchEffect的使用

103 阅读4分钟

Vue3中watch和watchEffect的使用

1. watch

1.1. 基本用法一:监视ref定义的响应式数据-[基本类型],直接写数据名字,监视的是value的值

<template>
    <h2>sum: {{ sum }}</h2>
    <button @click="add">add</button>
</template>
<script lang="ts" setup>
    import { ref, watch, reactive, watchEffect  } from 'vue';
    let sum = ref(0);
    const add = () => {
        sum.value++;
    }; 
    //解除监视
    const stopWatch = watch(sum, (newVal, oldVal) => {
        console.log('sum变化了:', newVal, oldVal);
        if(newVal >= 10) {
            stopWatch();
            console.log('解除了监视');
        }
    })
</script>

image.png

image-1.png

1.2. 基本用法二:监视ref定义的响应式数据-[对象类型],监视的是地址值,如果想要对象内部的数据,要开启深度监视[deep: true]

  • 没有加deep: true,默认是浅层监视,加上deep: true,开启深度监视,监视person.value的地址值和内部的数据
  • immediate: true,默认是false,开启后,会立即执行一次回调函数
<template>
    <h2>person: {{ person }}</h2>
    <button @click="person.name += '~'">add-name</button> | 
    <button @click="person.age++">add-age</button> | 
    <button @click="changePerson">changePerson</button> 
</template>
<script lang="ts" setup>
    import { ref, watch, reactive, watchEffect  } from 'vue';
    let person = ref({
        name: '张三',
        age: 18 
    })
    // 没有加deep: true,默认是浅层监视,只监视person.value的地址值,只有 person.value变化了才会触发
    const changePerson = () => {
        person.value = {name: '李四', age: 20}
    }
    // 加上deep: true,开启深度监视,监视person.value的地址值和内部的数据
    watch(person, (newVal, oldVal) => {
        console.log('person变化了:', newVal, oldVal);
    }, { deep: true , immediate: true}) 
</script>

gif1.gif

1.3. 基本用法三:监视reactive定义的响应式数据,默认开启了深度监视,而且无法关闭深度监视

<template>
    <h2>person2: {{ person2 }}</h2>
    <button @click="person2.name += '~'">add-name</button> | 
    <button @click="person2.age++">add-age</button> | 
    <button @click="person2.job.salary++">add-salary</button> | 
    <button @click="changePerson2">changeperson2</button> 
</template>
<script lang="ts" setup>
    import { ref, watch, reactive, watchEffect  } from 'vue';
    let person2 = reactive({
        name: '张三',
        age: 18,
        job: {
            salary: 20
        }
    })
    const changePerson2 = () => {
        // person2= {name: '李四', age: 20}
        Object.assign(person2, {name: '李四', age: 20})
    }
    // 地址没有变,没有真正的替换,只是重新分配了属性值
    watch(person2, (newVal, oldVal) => {
        console.log('person2变化了:', newVal, oldVal);
    })
</script>

gif2.gif

1.4. 基本用法四:监视ref或reactive定义的【对象类型】数据中的某个属性,注意点如下:

  • 若该属性值不是【对象类型】,需要写成函数形式。
  • 若该属性值是依然是【对像类型】,可直接编,也可写成函数,建议写成函数。
  • 结论:监视的要是对象里的属性,那么最好写函数式,注意点:若是对象监视的是地址值,需要关注对象内部,需要手动开启深度监视。
<template>
    <h2>Person3: {{ person3 }}</h2>
    <button @click="person3.name += '~'">add-name</button> | 
    <button @click="person3.age++">add-age</button> | 
    <button @click="changePerson3">changePerson3</button> 
</template>
<script lang="ts" setup>
    import { ref, watch, reactive, watchEffect  } from 'vue'; 

    let person3 = reactive({
        name: '张三',
        age: 18,
        job: {
            salary: 20
        }
    })
    const changePerson3 = () => {
        // person3.job = {salary: 30}
        person3.job.salary = 30
    }
    // 监视person3中的job属性,该属性是对象类型,可以直接写,也可以写函数, 推荐写函数:() => person3.job
    // (不写函数,[person3.job = {salary: 30}]整体变化会监视不到)
    watch(() => person3.job, (newVal, oldVal) => {
        console.log('person3变化了:', newVal, oldVal);
    }, { deep: true })
</script>

image-2.png

1.5. 基本用法五:情况五:监视上面几种情况的多个数据:

<template>
        <h2>person2: {{ person2 }}</h2>
        <button @click="person2.name += '~'">add-name</button> | 
        <button @click="person2.age++">add-age</button> | 
        <button @click="person2.job.salary++">add-salary</button> | 
        <button @click="changePerson2">changeperson2</button> 
        <h2>Person3: {{ person3 }}</h2>
        <button @click="person3.name += '~'">add-name</button> | 
        <button @click="person3.age++">add-age</button> | 
        <button @click="changePerson3">changePerson3</button> 
</template>
<script lang="ts" setup>
    import { ref, watch, reactive, watchEffect  } from 'vue'; 
    
    let person2 = reactive({
        name: '张三',
        age: 18,
        job: {
            salary: 20
        }
    })
    let person3 = reactive({
        name: '张三',
        age: 18,
        job: {
            salary: 20
        }
    })
    const changePerson3 = () => {
        // person3.job = {salary: 30}
        person3.job.salary = 30
    }
    watch([() => person2.name, person3.job], (newVal, oldVal) => {
        console.log('多个数据变化了:', newVal, oldVal);
    }, { deep: true })
</script>

监视的person2.name, person3.job的属性发生变化,console.log('多个数据变化了:', newVal, oldVal);就会执行,点击其他不执行,而且会合并到同一个数组里

gif3.gif

image-3.png

2.watchEffect

立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行该函数,不需要手动传入要监视的数据,会自动收集依赖,只要回调函数中用到了响应式数据,就会自动收集依赖

<template>
    <h2>Person3: {{ person3 }}</h2>
    <button @click="person3.name += '~'">add-name</button> | 
    <button @click="person3.age++">add-age</button> | 
    <button @click="changePerson3">changePerson3</button> 
</template>
<script lang="ts" setup>
    import { ref, watch, reactive, watchEffect  } from 'vue'; 

    let person4 = reactive({
        name: '张三',
        age: 18,
        job: {
            salary: 20
        }
    })

    let changePerson4 = () => {
        person4.job.salary = 30
    }
    watchEffect(() => {
        // 用到了哪些属性,那就监视哪些属性,当这些属性变化时,就会重新执行这个函数
        const x1 = person4.name
        const x2 = person4.job.salary
        console.log('watchEffect:', x1, x2)
    })
</script>

用到了[person4.name, person4.job.salary]属性,那就监视哪些属性,当这些属性变化时,就会重新执行这个函数

gif4.gif

3.watch对比watchEffect

  • 都能监听响应式数据的变化,不同的是监听数据变化的方式不同
  • watch:要明确指出监视的数据
  • watchEffect:不用明确指出监视的数据(函数中用到哪些属性,那就监视哪些属性)

4.Vue3中的watch只能监视以下四种数据:

  • ref定义的数据.
  • reactive定义的数据.
  • 函数返回一个值
  • 一个包含上述内容的数组.