Vue3 Composition API 响应式

16 min read

ref

ref接受一个参数值并返回一个响应式且可改变的 ref 对象。ref 对象拥有一个指向内部值的单一属性 .value。

相比于Vue2,用ref 的好处就是传值时可以不用再写this

reactive

Vue3提供了一个方法:reactive (等价于Vue2中的Vue.observable() )来赋予对象(Object) 响应式的特性

image-20210622094937561

  • 响应式转换是“深层的”:会影响对象内部所有嵌套的属性。基于 ES2015 的 Proxy 实现,返回的代理对象__不等于__原始对象。建议仅使用代理对象而避免依赖原始对象

  • 响应型对象(reactive object) 一旦被销毁或展开,其响应式特性(reactivity)就会丢失。

  • Proxy对象是目标对象的一个代理器,任何对目标对象的操作(实例化,添加/删除/修改属性等等),都必须通过该代理器。因此我们可以把来自外界的所有操作进行拦截和过滤或者修改等操作

ref 和 reactive 一个针对原始数据类型,而另一个用于对象,这两个API都是为了给JavaScript普通的数据类型赋予响应式特性(reactivity)。根据Vue3官方文档,这两者的主要区别在于每个人写JavaScript时的风格不同,有人喜欢用原始数据类型(primitives),把变量单独拎出来写;而有人喜欢用对象(Object),把变量当作对象里的属性,都写在一个对象里头

<template>
  <img alt="Vue logo" src="./assets/logo.png">
  <h1>{{count}}</h1>
  <h1>num:{{num}}</h1>
  <h2>{{double}}</h2>
  <p v-for="item in arr" :key="item">{{item}}</p>
  <h3>{{obj.name}}</h3>
  <button @click="increase">count+1</button>
  <button @click="handleClick">num+1</button>
  <HelloWorld msg="test"/>
</template>

<script>
import {computed, ref, reactive, toRefs, onMounted, watch} from "vue";
import HelloWorld from "@/components/HelloWorld";
export default {
  name: 'App',
  components:{
    HelloWorld
  },
  setup(){
     const count = ref(0);
     const increase = () => { count.value++} ;
     const double = computed(()=> count.value * 2);

     const data =  reactive({
       num :1,
       arr:[],
       obj:{},
       handleClick:()=> data.num ++
     });

    data.arr[0]= "arr"
    data.arr.push("arr1");
    data.obj.name="obj"

    onMounted(()=>{
      console.log('2021/6/18',2021/6/18)
    })

    watch([count,()=>data.num],((value, oldValue) => {
      console.log('value',value)
      console.log('oldValue',oldValue)
    }))

     return{
       count,
       increase,
       double,
       ...toRefs(data)
     }
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>