详解Vue中的ref和reactive函数 | 青训营笔记

138 阅读2分钟

详解Vue中的ref和reactive函数 | 青训营笔记

这是我参与「第四届青训营 」笔记创作活动的第9天

1.    ref函数

  • 作用:定义一个响应式的数据
  • 语法:  const xxx = ref(initValue)
    • 创建一个包含响应式数据的引用对象 【引用实现的实例对象】 (RefImpl对象【reference-implement】,简称ref 对象)。
    • JS中操作数据xxx.value【在ref对象中可以看到value需要用getter】
    • 模板中读取数据:不需要 .value,直接:<div>{{xxx}}</div> 【Vue3会自动解析到是ref对象,拿value值】

image.png

image.png

  • 备注:
    • 接收的数据可以是:基本类型、也可以是对象类型
    • 基本类型的数据:响应式依然是靠Object.defineProperty()的get set完成的
    • 对象类型的数据:内部 “ 求助 ” 了Vue3.0中的一个新函数—— reactive函数 【封装了proxy的具体实现】

2.    reactive函数

  • 作用: 定义一个对象类型响应式数据基本类型不要用它,要用ref函数

  • 语法:const 代理对象= reactive(源对象)接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象【利用proxy可以实现响应式,getter / setter也可但启用es6的proxy】

  • reactive定义的响应式数据是“深层次的”。

  • 内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据进行操作【且操作可以被Vue捕获 --> 数据劫持】

3.    具体的代码书写解析如下:

<script>
import { ref, reactive } from "vue";
export default {
  name: "App",
  setup() {
    // 数据
    let name = ref("张三"); // 使用数据劫持,捕获后根据逻辑更新页面【是ref对象,有getter和setter】
    let age = ref(18);
    let job = {
      //  成为proxy代理对象而不是ref对象【es6的proxy】
      type: "前端工程师",
      salary: "30K",
      a: {
        b: {
          c: "最深的",
        },
      },
    };
    let hobby = ["抽烟", "喝酒", "烫头"];

    let job1 = ref(job); // ! 注意:这里ref和reactive都套住了同一个job,obj1改则obj2也会改,一同更新数据
    let hobby1 = ref(hobby);
    // let sex = reactive("female"); // 可以使用但会警告
    let job2 = reactive(job);
    let hobby2 = reactive(hobby);

    function changeInfo() {
      /**
       * ? 0.直接改:
       */
      console.log(name, age);
      name = "小五";
      age = 19;  // 以这种方式无法更新数据并实现数据代理
      /**
       * ? 1. 用ref:
       */
      console.log(name, age);
      name.value = "李四";
      age.value = 48; // 基本数据类型要加上value来改
      console.log(job1.value); // 对象会转为proxy
      job1.value.type = "UI设计师"; // 无需再加一层 .value
      job1.value.salary = "60K";
      /**
       * ? 2. 用reactive:
       */
      console.log(job2); // Proxy {type: 'UI设计师', salary: '60K', a: {…}}  'female'
      // sex = "male"; // 修改不了
      // sex.value = "male"; // 报错:读不到value属性
      job2.type = "后端工程师";
      job2.salary = "88k";
      job2.a.b.c = "修改了的"; // 深层次的对象结构也可以检测到改动
      /**
       * ? 3. 检测数组改变:【reactive同样可以检测数组改变】
       * * 且别于Vue2必须经过指定方法改变数据才可以达到响应式,Vue3中修改更简易
       */
      hobby1[0] = "学习哦哈哈哈"; // 改不了
      hobby2[0] = "学习哦哈哈哈"; // ! 有效,且一改则hobby、hobby1、hobby2都改
    }

    //返回一个对象(常用)
    return {name,age,job1,job2, 
      // sex,
      hobby, hobby1, hobby2, changeInfo,
    };
  },

};
</script>

3.    reactive对比ref

一般用 reactive 比较多;一般会把基本数据类型封装到对象内 -> 用 reactive 定义对象类型

  • 从定义数据角度对比:
    • ref用来定义:基本类型数据
    • reactive用来定义:对象(或数组)类型数据
    • 备注:ref也可以用来定义对象(或数组)类型数据, 它内部会自动通过****reactive 转为代理对象
  • 从原理角度对比:
    • ref通过Object.defineProperty() 的get与set来实现响应式(数据劫持)。
    • reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源对象内部的数据。
  • 从使用角度对比:
    • ref 定义的数据:操作数据需要 .value,读取数据时模板中直接读取不需要 .value
    • reactive 定义的数据:操作数据与读取数据:均不需要 .value