vue3中reactive对比ref watch watchEffect函数

vue3中reactive对比ref

从定义数据角度对比:

  1. ref用来定义: 基本数据类型
  2. reactive用来定义: 对象(或数组)类型数据
    备注: ref也可以用来定义对象(或数组)类型数据,它内部会自动通过reactive转为代理对象

从原理角度对比:
3. ref通过Object.defineProperty()的get和set来实现响应式(数据劫持)
4. reactive通过Proxy来实现响应式(数据劫持),并通过Reflect操作源对象内部的数据

从使用角度对比:
6. ref定义数据:操作数据需要 .value ,读取数据时模板中直接读取不需要 .value
7. reactive 定义的数据: 操作数据和读取数据均不需要 .value

vue3中的watch

1.监视reactive定义的响应式数据的时候:oldValue无法获取到正确的值,强制开启了深度监视(deep配置无效)
2.监视reactive定义的响应式数据中某个属性的时候:deep配置有效
具体请看下面代码以及注释

watch([sum,msg], (newValue,oldValue)=>{
console.log(‘新的值’,newValue); //[‘sum的newValue’, ‘msg的newValue’]
console.log(‘旧的值’,oldValue); //[‘sum的oldValue’, ‘msg的oldValue’]
},{immediate: true,deep:true})
immediate:初始化的时候执行一次; deep:深度监听,慎用,很浪费资源

<template>
  <h1>当前求和为: {{sum}}</h1>
  <button @click="sum++">点我+1</button>
  <hr>
  <h1>当前信息为: {{msg}}</h1>
  <button @click="msg+='!' ">修改信息</button>
  <hr>
  <h2>姓名: {{person.name}}</h2>
  <h2>年龄: {{person.age}}</h2>
  <button @click="person.name += '~' ">修改姓名</button> <button @click="person.age++">增长年龄</button>
</template>

<script>
    //使用setup的注意事项
    import { watch,ref,reactive } from 'vue'

    export default {
        name: 'test5',
        props: ['msg'],
        emits:['hello'],
        setup(){
            let sum  = ref(0)
            let msg = ref('你好啊')
            let person = reactive({
                name: '张三',
                age: 18,
                job:{
                    salary: '15k'
                },
            })
            //由于这里的this是指的是undefined,所以使用箭头函数
            //情况一:监视ref所定义的一个响应式数据
            // watch(sum, (newValue,oldValue)=>{
            //     console.log('新的值',newValue);
            //     console.log('旧的值',oldValue);
            // })

            //情况二:监视ref所定义的多个响应式数据
            watch([sum,msg], (newValue,oldValue)=>{
                console.log('新的值',newValue); //['sum的newValue', 'msg的newValue']
                console.log('旧的值',oldValue); //['sum的oldValue', 'msg的oldValue']
            },{immediate: true,deep:true}) //这里vue3的deep是有点小问题的,可以不用deep,(隐式强制deep)

            //情况三:监视reactive定义的所有响应式数据,
            //1.此处无法获取正确的oldValue(newValue与oldValue是一致值),且目前无法解决
            //2.强制开启了深度监视(deep配置无效)
            /**
            * 受到码友热心评论解释: 此处附上码友的解释供大家参考:
            * 1. 当你监听一个响应式对象的时候,这里的newVal和oldVal是一样的,因为他们是同一个对象【引用地址一样】,
            *    即使里面的属性值会发生变化,但主体对象引用地址不变。这不是一个bug。要想不一样除非这里把对象都换了
            * 
            * 2. 当你监听一个响应式对象的时候,vue3会隐式的创建一个深层监听,即对象里只要有变化就会被调用。
            *    这也解释了你说的deep配置无效,这里是强制的。
            */
            watch(person, (newValue,oldValue)=>{
                console.log('新的值',newValue); 
                console.log('旧的值',oldValue);
            })

            //情况四:监视reactive对象中某一个属性的值,
            //注意: 这里监视某一个属性的时候可以监听到oldValue
            watch(()=>person.name, (newValue,oldValue)=>{
                console.log('新的值',newValue);  
                console.log('旧的值',oldValue);
            })

            //情况五:监视reactive对象中某一些属性的值
            watch([()=>person.name,()=>person.age], (newValue,oldValue)=>{
                console.log('新的值',newValue);  
                console.log('旧的值',oldValue);
            })

            //特殊情况: 监视reactive响应式数据中深层次的对象,此时deep的配置奏效了
            watch(()=>person.job, (newValue,oldValue)=>{
                console.log('新的值',newValue);  
                console.log('旧的值',oldValue);
            },{deep:true}) //此时deep有用

            return {
                sum,
                msg,
                person,
            }
        },
        
    }
</script>

watchEffect函数

watchEffect( ()=>{这里面你用到了谁就监视谁,里面就发生回调} )

  1. watch的套路是:既要指明监视的属性,也要指明监视的回调
  2. watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性
  3. watchEffect有点像computed: 但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值

watchEffect特点

不需要手动传入依赖(不用指定监听对象)
无法获取原始值,只能获取更新后的值
立即执行(在onMounted前调用)
一些异步操作放里面更加的合适

const count = ref(0)
watchEffect(() =>{
 	console.log(count.value)
})

setTimeout(() => {
  count.value++
}, 1000)

</script>

停止监听

停止监听和watch一样的

const stop = watchEffect(() => {
  /* ... */
})
// 停止监听
stop()

更改监听时机(更改副作用刷新时机)

watchEffect两个参数(副作用回调函数,{flush:‘pre’,onTrack(){},onTrigger(){}})

onTrack 和 onTrigger 选项可用于调试侦听器的行为。

  • onTrack 将在响应式 property 或 ref 作为依赖项被追踪时被调用。
  • onTrigger 将在依赖项变更导致副作用被触发时被调用。

flush取值

flush取值:
pre (默认)
post (在组件更新后触发,这样你就可以访问更新的 DOM。这也将推迟副作用的初始运行,直到组件的首次渲染完成。)
sync (与watch一样使其为每个更改都强制触发侦听器,然而,这是低效的,应该很少需要)

清除副作用

副作用是指一个函数在返回值时还干了其它事(该函数称之为副作用函数)如:修改一个变量、设置一个对象的成员、终端打印日志、修改DOM、时间监听或订阅、等等

watchEffect可在第一个参数(函数)里传入一个参数onInvalidate 用来清除副作用

onInvalidate 执行时间:
副作用即将重新执行时(监听对象改变时)
侦听器被停止 (如果在 setup() 或生命周期钩子函数中使用了 watchEffect,则在组件卸载时)

 let stop = watchEffect((onInvalidate) => {
      console.log(count.value++,);
      // onInvalidate(() => {
      //   stop()
      //   console.log('c');

      // })
    }, {
      flush: 'pre',
      onTrack(e) {
        console.log('a', e);
      },
      onTrigger(e) {
        console.log('b', e);
      }
    })
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜空孤狼啸

你的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值