vue3.0 composition api

12 篇文章 1 订阅

  • vue2中如果新增一个功能,需要在data中添加数据,在methodscomputedwatch中添加逻辑,那么数据与业务逻辑是分散的。
  • 这种碎片化使得理解和维护复杂组件变得困难。选项的分离掩盖了潜在的逻辑问题。此外,在处理单个逻辑关注点时,我们必须不断地“跳转”相关代码的选项块。
  • 如果我们能够将与同一个逻辑关注点相关的代码配置在一起会更好。而这正是组合式 API 使我们能够做到的在vue3中,composition API解决了数据与业务逻辑分散的问题。
  • setup()函数是vue3中专门新增的方法,可以理解为Composition Api的入口,其中在setup函数中由于此时还未创建vue实例,因此是没有办法访问this

简单demo

  • 下面是一个关于composition api的简单应用
<template>
  <div>
    <p>{{ count }}</p>
    <p>{{ double }}</p>
    <button @click="increase">add</button>
  </div>
</template>

<script>
import { computed, ref } from 'vue';
export default {
  setup() {
    const count = ref(0);
    const double = computed(() => {
      return count.value * 2
    })

    function increase(){
      count.value ++;
    }

    return {
      count,
      double,
      increase
    }
  }
}
</script>

setup参数

  • propssetup 函数中的第一个参数是 props。正如在一个标准组件中所期望的那样,setup 函数中的 props 是响应式的,当传入新的 prop 时,它将被更新
  • context:上下文对象,其中包含下面属性
    在这里插入图片描述
setup(props, context) {
    context.attrs
    context.slots
    context.parent
    context.root
    context.emit
    context.refs
  }

setup生命周期

选项式 APIHook inside setup
beforeCreateNot needed*
createdNot needed*
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeUnmountonBeforeUnmount
unmountedonUnmounted
errorCapturedonErrorCaptured
renderTrackedonRenderTracked
renderTriggeredonRenderTriggered
  • 当钩子在生命周期中被执行
export default {
  setup() {
    // mounted
    onMounted(() => {
      console.log('Component is mounted!')
    })
  }
}

响应式API

reactive

reactive接受一个对象(json/arr),返回一个响应式对象

<template>
  <p>{{state.count}}</p>
  <button @click="addCount">CountAdd</button>
</template>
export default {
  setup () {
     let obj = {
      count: 1
    };
    let state = reactive(obj);
    function addCount() {
      state.count++;
      console.log('state',state);
      console.log('obj', obj);
    }
    return {
     state,
     addCount
    }
  }
}

在这里插入图片描述

  • 注:reactive接受的参数必须是一个对象;
    且通过reactive创建的对象,当修改响应式数据之后,原对象也会发生变化

ref

在上面了解到,通过reactive可以将一个普通对象转换为一个响应式对象,但如果需要将一个简单类型的数据转为响应式数据,可通过ref实现

  • ref的本质其实还是reactive
    系统会根据我们给ref传入的值将它转换为如下:ref(xxx) ----> reactive({value: xxx})
  • template中使用ref的值不需要通过value获取,但在JS中使用ref的值必须通过value获取
<template>
  <p>{{count}}</p>
  <button @click="addCount">CountAdd</button>
</template>
setup () {
    let num = 4;
    let count = ref(num);
    function addCount() {
      count.value++;
      console.log('num',num);
      console.log('count', count);
    }
    return {
     count,
     addCount
    }
  }

在这里插入图片描述

refreactive区别:

  1. 如果在template里使用的是ref类型的数据,那么vue会自动添加.value
  2. 如果在template里使用的是reactive类型的数据,那么vue不会自动添加.value

Vue是如何决定是否需要自动添加.value

  1. Vue在解析数据之前,会自动判断这个数据是否是ref类型的,如果是就自动添加.value,如果不是就不自动添加.value

Vue是如何判断当前的数据是否是Ref类型的?

  1. 通过当前数据的__v_ref来判断的,由上图可以看到count__v_ref的值为true
  2. 如果有这个私有的属性,并且取值为true,那么就代表是一个ref类型的数据

isRefisReactive 这两个方法可以对 refreactive 的数据类型进行判断

toRefs与toRef

  • toRefs()函数可以将reactive()创建出来的响应式对象,转换为普通对象,只不过这个对象上的每个属性节点,都是ref类型的响应式数据
<template>
  <div>
    <p>{{ count }}</p>
    <button @click="increasement">add</button>
  </div>
</template>

<script>
import { computed, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onMounted, onUnmounted, onUpdated, reactive, ref, toRefs } from 'vue';
export default {
  setup(props, context) {

    const state = reactive({
      count: 0
    })

    const increasement = () => {
      state.count ++;
    }

    return {
      ...toRefs(state),
      increasement
    }
  }
}
</script>
  • toRef:概念:为源响应式对象上的某个属性创建一个ref对象,二者内部操作的是同一个数据值,更新时二者是同步的。相当于浅拷贝一个属性.
    区别ref: 拷贝的是一份新的数据单独操作,更新时相互不影响,相当于深拷贝
    场景:当要将某个propref传递给某个复合函数时,toRef很有用.
<template>
  <div>
    <p>{{ state.count }}</p>
    <p>{{ count1 }}</p>
    <p>{{ count2 }}</p>
    <button @click="increasement">add</button>
  </div>
</template>

<script>
import { computed, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onMounted, onUnmounted, onUpdated, reactive, ref, toRef, toRefs } from 'vue';
export default {
  setup(props, context) {

    const state = reactive({
      count: 0
    })

    const count1 = toRef(state, 'count');
    const count2 = ref(state.count);

    const increasement = () => {
      // state.count ++;   // state中count改变时,count1也会改变
      // count1.value ++;     // count1改变时,state中count也会改变
      count2.value ++;     // 只有count2改变,count与count1均不会改变
    }

    return {
      state,
      count1,
      count2,
      increasement
    }
  }
}
</script>

computed

  • 只读属性
import { ref, computed } from 'vue';
export default {
    setup () {
        const count = ref(0);
        const double = computed(()=> count.value + 1);//1

        double++;//Error: "double" is read-only

        return {
           count,
           double
        };
    }
};
  • 可读可写属性
// 创建一个 ref 响应式数据
const count = ref(1)

// 创建一个 computed 计算属性
const plusOne = computed({
  // 取值函数
  get: () => count.value + 1,
  // 赋值函数
  set: val => {
    count.value = val - 1
  }
})

// 为计算属性赋值的操作,会触发 set 函数
plusOne.value = 9
// 触发 set 函数后,count 的值会被更新
console.log(count.value) // 输出 8

watch

  • 用于监听数据的变化
  • 参数:
    • 参数1:需要监听的数据项,类型需要是ref类型,一个reactive对象,数组,或者getter/effect函数
    • 参数2:回调函数
    • 选项对象,可以设置immediatedeep
  • 返回值:是取消监听的函数
setup(props, context) {

    const state = reactive({
      count: 0
    })

    // watch(state, (newVal, oldVal) => {
    //   console.log(newVal, oldVal);
    // })
    watch(() => state.count, (newVal, oldVal) => {
      console.log(newVal, oldVal);
    })

    setInterval(() => {
      state.count++;
    }, 1000)

    return {
      state
    }
  }
  • 监听清除: 在setup()函数内创建的watch监视,会在当前组件被销毁的时候自动停止。如果想要明确的停止某个监视,可以调用watch()函数的返回值即可
// 创建监视,并得到 停止函数
const stop = watch(() => {
  /* ... */
})

// 调用停止函数,清除对应的监视
stop()

watchEffect

  • watchEffectwatch 类似,可以监听属性的变化
  • watch的不同:
    • watchEffect不需要指定监听属性,可以自动收集依赖,只要我们回调中引用了响应式的属性,那么这些属性变更的时候,这个回调都会执行,而watch只能监听指定的属性而做出变更(v3中可以同时监听多个
    • watch可以获取到新值和旧值,而watchEffect获取不到
    • watchEffect会在组件初始化的时候就会执行一次与computed同理,而收集到的依赖变化后,这个回调才会执行,而watch不需要,除非设置了指定参数。
import { watchEffect, ref } from 'vue'
setup () {
    const userID = ref(0)
    watchEffect(() => console.log(userID))
    setTimeout(() => {
      userID.value = 1
    }, 1000)

    /*
      * LOG
      * 0 
      * 1
    */

    return {
      userID
    }
 }

文档参考:
Composition API详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值