• 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>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88

    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>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    停止监听

    停止监听和watch一样的

    const stop = watchEffect(() => {
      /* ... */
    })
    // 停止监听
    stop()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

    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);
          }
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    Python学习笔记第四十四天(NumPy 统计函数)
    【Unity3D赛车游戏优化篇】新【八】汽车实现镜头的流畅跟随,以及不同角度的切换
    java-net-php-python-springboot社区志愿者管理系统计算机毕业设计程序
    路由 —— 源站路由 + 策略路由
    基于模糊BP神经网络轨迹跟踪(Matlab代码实现)
    SPARKSQL3.0-Spark兼容多版本Hive源码分析
    AtCoder Beginner Contest 311 D(dfs/bfs)
    C++ Reference: Standard C++ Library reference: C Library: cctype: isalnum
    Node.js 入门教程 11 Node.js 从命令行接收参数
    第二章计算机网络参考模型
  • 原文地址:https://blog.csdn.net/qq_43940789/article/details/127818381