vue3的watch、watchEffect、computed

本文对比了Vue2和Vue3中如何使用computed属性,以及ref和reactive的不同。讲解了如何创建计算属性,ref的两种使用方法,watch的侦听机制,watchEffect的自动依赖收集和副作用清除。还讨论了watch和watchEffect的主要区别。
摘要由CSDN通过智能技术生成

区别

Vue2

使用的是computed属性

Vue3

需要在setup函数中使用computed方法来编写一个计算属性

computed

方法1.接收一个getter函数,并为 getter 函数返回的值,返回一个不变的 ref 对象

<template>
<div>
{{ fullname }}
</div>
</template>
  
<script>
import { reactive,ref,toRef,toRefs ,computed} from 'vue';
export default {
 setup(){
  const name=ref("dls")
  const age=ref(17)
   
  const fullname=computed(()=>{
    return name.value+age.value
  })
  return{
   fullname
  }
 }

}
</script>
<style>
</style>

方法2.接收一个具有 get 和 set 的对象,返回一个可变的(可读写)ref 对象

<template>
  {{ fullName }}
  <button @click="changeName">change</button>
</template>
 
<script>
import { computed, reactive } from 'vue';
export default {
  name: 'App',
  setup() {
    const names = reactive({
      firstName: '冲啊',
      lastName: '迪迦奥特曼'
    });
    // 会返回一个ref对象
    const fullName = computed({
      set(newValue) {
        const tempNames = newValue.split(' ');
        names.firstName = tempNames[0];
        names.lastName = tempNames[1];
      },
      get() {
        return names.firstName + names.lastName;
      }
    });
    // 设置值
    const changeName = () => {
      fullName.value = fullName.value === '冲啊迪迦奥特曼' ? '神秘的 宇宙人' : '冲啊 迪迦奥特曼';
    };
 
    return {
      fullName,
      changeName
    };
  }
};
</script>

Watch

  • watch需要侦听特定的数据源,并在回调函数中执行副作用
  • 默认情况下它是惰性的,只有当被侦听的源发生变化时才会执行回调
  • 与watchEffect的比较,watch允许我们懒执行副作用(第一次不会直接执行)
  • 更具体的说明当哪些状态发生变化时,触发侦听器的执行
  • 访问侦听状态变化前后的值

侦听单个数据源

watch侦听函数的数据源有两种类型:

  • 一个getter函数:但是该getter函数必须引用可响应式的对象(比如reactive或者ref)
  • 直接写入一个可响应式的对象,reactive或者ref(比较常用的是ref)

解构
 () => ({ ...star })
   //其实也就等同于,因为将star解构后还是需要让他包裹在对象中
   //箭头函数无法识别这个{}是函数体还是对象
 () =>{
   return {...star}
 }

同理内部包裹的是数组时:

是ref对象时:
<template>
  <div>
  <h1>
  {{ star }}
  </h1>
  <button @click="change">change</button>
  </div>
  </template>
  <script>
  import { ref, reactive, watch } from 'vue';
export default {
  setup() {
/**
* 一、如果ref响应式对象中的是基本数据类型
*/
const star = ref('123');
// const star = ref('123');
// 改变
const change = () => (star.value = star.value === 'coder' ? '123' : 'coder');
// 那么直接这样传入即可,拿到的是value值本身
watch(star, (newValue, oldValue) => {
  console.log('newValue:', newValue, 'oldValue:', oldValue);
});
--------------------------------------------------------------------------------------
/**
* 二、如果ref对象中的是对象数据,那么也需要结构 () => ({...star.value})
如果不结构,拿到的是ref对象
*/
const star = ref({ name: '123', age: 14 });
// 改变
const change = () => (star.value.name = star.value.name === 'coder' ? 'pppp' : 'coder');
// 那么需要结构,如果不结构,拿到的是ref对象
watch(
  () => ({ ...star.value }),
  (newValue, oldValue) => {
    console.log('newValue:', newValue, 'oldValue:', oldValue);
  }
);

    return {
      star,
      change
    };
  }
};
</script>

  <style lang="scss" scoped></style>
是reactive对象时
<template>
  <div>
    <h1>
      {{ star.name }}
    </h1>
    <button @click="change">change</button>
  </div>
</template>
<script>
import { ref, reactive, watch } from 'vue';
export default {
  setup() {
    const star = reactive({ name: '123', age: 15 });
    // 改变
    const change = () => (star.name = star.name === 'coder' ? '123' : 'coder');
    /**
     * 一、如果直接传入reactive对象,那么打印出的也是两个reactive对象
     */
    watch(star, (newValue, oldValue) => {
      console.log('newValue:', newValue, 'oldValue:', oldValue);
    });
---------------------------------------------------------------------------------------
    /**
     * 二、如果希望获得普通对象,结构一下
     */
    watch(
      () => ({ ...star }),
      (newValue, oldValue) => {
        console.log('newValue:', newValue, 'oldValue:', oldValue);
      }
    );
    return {
      star,
      change
    };
  }
};
</script>
 
<style lang="scss" scoped></style>

因为在源码中,reactive对象和ref对象的处理方法不一样(ref中已经带有了.value后缀)

侦听多个数据源

<template>
  <div>
    <h1>
      {{ star.name }}
    </h1>
    <button @click="change">change</button>
  </div>
</template>
<script>
import { ref, reactive, watch } from 'vue';
export default {
  setup() {
    // ref对象
    const coder = ref('know');
    // reactive对象
    const star = reactive({ name: '123', age: 15 });
    // 改变
    const change = () => {
      star.name = 'coder';
      coder.value = 'unKnow';
    };
    // 传入数组即可                      // 对应结构
    watch([coder, () => ({ ...star })], ([newCoder, newStar], [oldCoder, oldStar]) => {
      console.log(newCoder, newStar, '----', oldCoder, oldStar);
    });
 
    return {
      star,
      change
    };
  }
};
</script>
 
<style lang="scss" scoped></style>

watch的选项

配置第三个参数 :

  • deep : 是否深度监听
  • immediate : 是否立即执行
<template>
  <div>
    <h1>
      {{ info.name }}
    </h1>
  </div>
</template>
<script>
import { ref, reactive, watch } from 'vue'
export default {
  setup() {
    // reactive对象
    const info = reactive({
      name: '123',
      age: 15,
      friend: { name: '456' }
    })
    watch(
      () => {
        const obj = { ...info }
        // 因为有两层,需要自己结构下,否则返回的是proxy
        obj.friend = { ...obj.friend }
        return obj
      },
      (newValue, oldValue) => {
        console.log(newValue, oldValue)
      },
      {
        // 如果有多层,需要加上deep
        deep: true,
        // 立即执行
        immediate: true
      }
    )
 
    return {
      info
    }
  }
}
</script>
 
<style lang="scss" scoped></style>

WatchEffect

  • 自动收集响应式数据的依赖
  • watchEffect传入的函数会被立即执行一次,并且在执行的过程中会收集依赖
  • 只有收集的依赖发生变化时,watchEffect传入的函数才会再次执行

区别

watch 不同,watchEffect 不需要明确地监视特定的数据,它会自动追踪在执行过程中访问的所有响应式数据,并在其中任何一个数据发生变化时触发。

用法

在最开始就会执行一次watcheffect,本质是要执行回调的函数,因此可以回调函数设置自己命名的函数(推荐用箭头函数)

<template>

<div>
{{ age }}-{{ name }}
<button @click="click">1</button>
<button @click="click2">2</button>
</div>
</template>

<script>

import { reactive,ref,watchEffect} from 'vue';
export default {
 setup(){
  const name=ref("dls")
  const age=ref(17)
   //如果里面没有写入name的话,执行name的变化不会触发监听
  watchEffect(()=>{
    console.log(age.value,name.value)
  })
  const click=()=>{
    age.value++
  }
  const click2=()=>{
   name.value="hhh"
  }
  return{
    name,
    age,
    click,
    click2
  }
 }
}
</script>

<style>

</style>

watchEffect的停止监听

假如,某些情况想要停止监听,那么可以获取watchEffect的返回值函数,调用该函数即可,这是因为 watchEffect 返回的函数是用于取消副作用的。

停止监听的方法通常与命名没有直接关系:它通常是由函数或对象的方法提供的。在 Vue 3 中,watchEffect 返回一个停止函数,这个函数通常被命名为你选择的变量名(例如,stopunwatch),但实际的名称可以根据你的代码风格和偏好来选择。

<template>

<div>
{{ age }}-{{ name }}
<button @click="click">1</button>
<button @click="click2">2</button>
</div>
</template>

<script>

import { reactive,ref,watchEffect} from 'vue';
export default {
 setup(){
  const name=ref("dls")
  const age=ref(17)
   //要先声明一个值来获取它返回的函数
  const xx=watchEffect(()=>{
    console.log(age.value,name.value)
  })
  const click=()=>{
    age.value++
    if (age.value > 22) {
        // 停止监听
        xx();
      }
  }
  const click2=()=>{
   name.value="hhh"
  }
  return{
    name,
    age,
    click,
    click2
  }
 }
}
</script>

<style>

</style>

watchEffect清除副作用

什么是清除副作用
  • 比如在开发中可能需要在侦听函数中执行网络请求,但是在网络请求还没有达到的时候,停止了侦听器,或者侦听器侦听函数被再次执行了
  • 那么上一次的网络请求应该被取消掉,这个时候就可以清除上一次的副作用

在Vue 3中,"副作用" 指的是与组件生命周期之外的操作相关的行为。这通常包括对 DOM 的操作、数据请求、订阅外部事件或资源等。副作用通常在组件的生命周期钩子函数之外执行,比如在 createdmountedupdated 钩子函数内。

Vue 3 提供了 watchwatchEffectonMounted 等函数来处理副作用。这些函数使你能够监视响应式数据的变化或执行特定的操作,而无需直接在模板中进行 DOM 操作或数据请求。

使用方法
  • 在给watchEffect传入的函数被回调时,其实可以获取到一个参数:onInvalidate(自己命名的,和上面的stop方法类似)
  • 当副作用即将重新执行 或者 侦听器被停止 时会执行该函数传入的回调函数
  • 可以在传入的回调函数中,执行一些清除工作

例如:此时获取的参数就命名为了test

<template>

<div>
{{ age }}-{{ name }}
<button @click="click">1</button>
<button @click="click2">2</button>
</div>
</template>

<script>

import { reactive,ref,watchEffect} from 'vue';
export default {
 setup(){
  const name=ref("dls")
  const age=ref(17)
  const xx=watchEffect((res)=>{
    console.log(age.value,name.value)
    res(()=>{ 
      console.log("去除副作用")
    })
  })
  const click=()=>{
    age.value++
    if (age.value > 22) {
        // 停止监听
        xx();
      }
  }
  const click2=()=>{
   name.value="hhh"
  }
  return{
    name,
    age,
    click,
    click2
  }
 }
}
</script>

<style>

</style>

watchEffect的时机

  • pre : 默认值,它会在元素 挂载 或者 更新 之前执行
  • post : 元素 挂载 或者 更新 之后执行
  • sync : 强制同步一起执行,效率很低,不推荐

和watch的区别

  • wathc必须指定数据源,watchEffect自动收集依赖
  • watch监听到改变,可以拿到改变前后的值,watchEffect只能拿到最新的值
  • watch第一次默认不执行,watchEffect默认直接执行一次
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值