24.compositionApi的watchEffect和re

2021-08-30  本文已影响0人  静昕妈妈芦培培

侦听数据的变化

在前面的Options API中,我们可以通过watch选项来侦听data或者props的数据变化,当数据变化时执行某一些操作。

在Composition API中,我们可以使用watchEffectwatch来完成响应式数据的侦听

watchEffect

当侦听到某些响应式数据变化时,我们希望执行某些操作,这个时候可以使用 watchEffect

watchEffect的基本使用

watchEffect的回调参数会在页面首页渲染的时候执行一次,通过这次执行,收集回调中依赖的响应式变量,然后监听其变化,一但侦听到变量值的改变,就会重新执行其回调函数
例:

<template>
  <div>
    <h1>名字: {{ name }} - 年纪: {{ age }}</h1>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年纪</button>
  </div>
</template>

<script>
import { ref, watchEffect } from "vue";
export default {
  setup() {
    const name = ref("why");
    const age = ref(18);

    //watchEffect的回调参数会在页面首页渲染的时候执行一次,通过这次执行,收集回调中依赖的响应式变量,然后监听其变化,
    //一但侦听到变量值的改变,就会重新执行其回调函数
    watchEffect(() => {
      //此函数中依赖的响应式对象为name和age,所以,不管name和age哪个的值发生改变,此回调函数都会重新执行
      console.log("name-", name.value, "age-", age.value);
    });

    const changeName = () => (name.value = "coder");
    const changeAge = () => age.value++;

    return {
      name,
      age,
      changeName,
      changeAge,
    };
  },
};
</script>

<style lang="scss" scoped></style>

watchEffect的停止侦听

watchEffect函数的返回值也是一个函数,调用此函数会停止侦听
如果在发生某些情况下,我们希望停止侦听,这个时候我们可以获取watchEffect的返回值函数,调用该函数即可。
案例:当age达到20的时候就停止侦听

<template>
  <div>
    <h1>名字: {{ name }} - 年纪: {{ age }}</h1>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年纪</button>
  </div>
</template>

<script>
import { ref, watchEffect } from "vue";
export default {
  setup() {
    const name = ref("why");
    const age = ref(18);
    //watchEffect函数会返回一个函数,调用此函数会停止侦听
    const stop = watchEffect(() => {
      console.log("age-", age.value);
    });

    const changeName = () => (name.value = "coder");
    const changeAge = () => {
       if(age.value > 20) {
          stop() //当age大于20时,停止侦听
       }
       age.value++
    };

    return {
      name,
      age,
      changeName,
      changeAge,
    };
  },
};
</script>

<style lang="scss" scoped></style>

watchEffect清除副作用

什么是清除副作用呢?
在我们给watchEffect传入的函数被回调时,其实可以获取到一个参数:onInvalidate
onInvalidate也是一个函数,接收一个回调函数作为参数
<template>
  <div>
    <h1>名字: {{ name }} - 年纪: {{ age }}</h1>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年纪</button>
  </div>
</template>

<script>
import { ref, watchEffect } from "vue";
export default {
  setup() {
    const name = ref("why");
    const age = ref(18);
    let timer = null;

    //watchEffect的回调函数参数在执行的时候也接收一个onInvalidate函数,
    //onInvalidate函数也接收一个回调函数作为参数
    //可以在onInvadiate函数的回调函数中做一些取消的处理,比如取消请求
    //当watchEffect侦听的变量值改变时,执行其回调函数前,会先执行回调接受的onInvadiate函数
    watchEffect((onInvadiate) => {
      timer = setTimeout(() => {
        console.log("模拟发送请求,携参:name,age");
      }, 3000);
      console.log("name-", name.value, "age-", age.value);
      onInvadiate(() => {
        //不管onInvadiate在watchEffect回到函数中的位置,只要回调函数执行,都优先执行onInvadiate
        //取消上次发送的请求
        clearTimeout(timer);
        console.log("onInvalidate");
      });
    });

    const changeName = () => (name.value = "coder");
    const changeAge = () => age.value++;

    return {
      name,
      age,
      changeName,
      changeAge,
    };
  },
};
</script>

<style lang="scss" scoped></style>

image.png

setup中使用ref

在讲解 watchEffect执行时机之前,我们先补充一个知识:在setup中如何使用ref或者元素或者组件?

<template>
  <div>
    <h1 ref="h1">hello world</h1>
  </div>
</template>

<script>
  import {ref} from 'vue'
  export default {
    setup() {
      const h1 = ref(null)
      return {
        h1
      }
    }
  }
</script>

watchEffect的执行时机

默认情况下,组件的更新会在副作用函数执行之后:
例:

默认情况下watchEffect会在组件挂载之前执行,所以watchEffect的回调会执行两次:

<template>
  <div>
    <h1 ref="h1">hello world</h1>
  </div>
</template>

<script>
import { ref, watchEffect } from "vue";
export default {
  setup() {
    let h1 = ref(null);
    //默认情况下watchEffect会在组件挂载之前执行,
    //所以watchEffect的回调会执行两次:
    //第一次执行时,组件还没挂载,h1.value为null
    //组加挂载成功后,h1.value的值变为h1Dom元素,watchEffect会再次执行,
    //因为watchEffect依赖h1这个响应式对象
    watchEffect(() => {
      //h1为h1DOM元素
      console.log("h1", h1.value);
    });

    return {
      h1,
    };
  },
};
</script>

<style lang="scss" scoped></style>

我们会发现打印结果打印了两次:

调整watchEffect的执行时机

如果我们希望在第一次的时候就打印出来对应的元素呢?

watchEffect函数接收第二个参数为一个对象,此对象中可以做一些配置

例:
<template>
  <div>
    <h1 ref="h1">hello world</h1>
  </div>
</template>

<script>
  import {ref, watchEffect} from 'vue'
  export default {
    setup() {
      let h1 = ref(null)
      watchEffect(() => {
        //h1为h1DOM元素
        console.log('h1', h1.value)
      }, {
        flush: 'post'//调整watchEffect的执行时机为元素挂载/更新之后执行
        //默认为'pre'  元素挂载/更新之前执行
      })

      return {
        h1
      }
    }
  }
</script>

<style lang="scss" scoped>

</style>
我们会发现第一次就获取到了元素

因为watchEffect的回调函数是在元素挂载之后才执行的,此时h1.value已经是h1dom元素了


image.png

此文档主要内容来源于王红元老师的vue3+ts视频教程

上一篇 下一篇

猜你喜欢

热点阅读