Vue3-组合式Api和响应式原理解读(二)_ref和reactive理解

739 阅读3分钟

ref的定义

接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象具有指向内部值的单个 property

ref的使用

在vue2里面,想要使一个数据变成响应式( 数据改变-> 视图改变 -> 数据改变 )都是在data函数中定义一个属性,用v-model绑定,那么在Vue3里面,该怎么在setup里面定义响应式数据呢?


下方代码作为参考

    <template>
      <div>ref的使用</div>
      <p>{{ count }} ----count</p>
      <p>{{ number }} ----number</p>
      <el-button @click="addCount" type="primary">添加count</el-button>
      <el-button @click="addNumber" type="primary">添加Number</el-button>
    </template>

<script>
/**
 *  ref 是一个函数,一般用来定义基本数据类型的响应式数据
 *  返回一个RefImpl对象,通过操作对象的vlaue属性,来实现响应式数据
 * */

import { defineComponent, ref } from "vue";

export default defineComponent({
  name: "App",
  setup() {
    let count = 20;
    const number = ref(10);
    
    function addNumber() {
      number.value++;
      console.log("addNumber函数触发,number原理上自增",number);
    }
    function addCount() {
      count += 1
      console.log("addCount函数触发,addCount原理上自增",count);
    }
    return { count, number, addNumber, addCount };
  },
});
</script>

如之前所说,setup是所有组合式API的入口,那么如我们之前习惯,在函数中定义一个变量count通过return返回count变量,在html视图模板中是可以正常使用变量count,那么我们通过触发addCount函数来改变数据,看视图是否发生变化?


使用平时习惯定义变量

ref数据.png


那么使用ref来定义数据呢?


ref响应式数据.png


通过以上代码来看,在vue3中,想实现响应式数据,需要通过ref来实现

ref 使用总结

    总结:
        在vue3中,想实现响应式数据,需要通过ref来实现
        通过操作refImpl对象的value值,来实现响应式数据
        这里操作的简单的数据类型(字符串,数值,布尔等)
        也可以操作复杂的数据类型,如数组、对象,
        但是一般操作复杂数据类型,我们会用到reactive
        使用ref来定义复杂数据类型,实际上内部是做了一层转换
        底层还是用reactive来实现的

reactive的定义

返回对象的响应式副本

响应式转换是“深层”的——它影响所有嵌套 property。在基于 ES2015 Proxy 的实现中,返回的 proxy 是等于原始对象的。建议只使用响应式 proxy,避免依赖原始对象。


以上摘自vue3官网文档描述reactive

我的理解:reactive是通过ES2015中的Proxy来实现对目标对象的一层代理,通过操作目标对象来返回一个代理对象,在vue3中想要获取复杂的响应式数据,都是通过操作代理对象来完成的,操作目标对象是不会发生响应式数据变化的

上图

reactive的使用

 <template>
  <div>reactive的使用</div>
  <h3>{{ userInfo.name }}</h3>
  <h3>{{ userInfo.age }}</h3>
  <h3>{{ userInfo.wife }}</h3>
  <el-button @click="updateUser" type="primary">更改对象</el-button>
</template>

<script>
/**
 *  reactive:返回的是一个proxy的代理对象,被代理的叫做目标对象
 *  把复杂的数据类型变成响应式数据。
 *  通过修改代理对象的值来达到响应式数据
 *  const proxy = reactive(obj): 接收一个普通对象然后返回该普通对象的响应式代理器对象
 *  响应式转换是“深层的”:会影响对象内部所有嵌套的属性
 *  内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据都是响应式的
 * */

import { defineComponent, reactive } from "vue";

export default defineComponent({
  name: "App",
  setup() {
    let obj = {
      name: "小明",
      age: 20,
      wife: {
        name: "小红",
        age: 18,
        cars: ["奔驰", "宝马", "特斯拉"],
      },
    };
    const userInfo = reactive(obj);
    let updateUser = () => {
      userInfo.name = "胖虎";
      console.log('通过更改假对象函数触发updateUser',obj, userInfo);
    };
    let updateWife = () => {
      obj.wife.name = "静香";
      console.log('通过更改真对象函数触发updateWife',obj, userInfo);
    };
    return { userInfo, updateUser };
  },
});
</script>

reactive响应式.png


通过看图跟上方代码以及控制台打印,我们可以知道通过reactive包裹的目标对象,使用proxy返回代理对象userInfo是可以实现响应式数据变化的小明变胖虎的,而直接去操作目标对象obj虽然可以达到目标对象的内容修改,但是无法实现响应式数据视图变化,胖虎的媳妇还是小红,得不到静香

reactive的总结

    在vue3代码中,在setup入口中的组合式API,响应式数据都是通过reactive来实现的,
    ref一般用来定义简单数据类型(数值,字符串,布尔等),
    reactive一般用来应以对象、数组,ref也可来定义复杂数据类型,
    但是会被转换成reactive,为了区分辨识度,
    我们统一使用ref来定义基本数据类型,reactive来定义复杂数据类型

下一节

ref和reactive实现响应式数据的原理


> 记录不易,希望能得到您的一个小手手,点赞👍是我坚持下去的动力
> 一起加油吧,如果理解错误,还请指正,尽快修改,谢谢大家