Skip to content

常用的Composition API

官方API文档

composion API 是一组api的组合,因此也叫组合API。包括:setup、ref、reactive、watchEffect等等。参考这里

setup

Vue3.x 新增的一个选项, 组件内使用 Composition API的入口

setup 执行时机是在 beforeCreate 之前执行

此函数返回的对象会被合并到组件上下文中

setup参数

js
export default defineComponent ({
  // props 父组件传递的props
  // context 提供Vue实例上常用的属性:attrs、slot、emit
  setup(props, context) {
      // const { name } = props // 结构会使props丢失响应性
  },
})

reactive、ref 与 toRefs

reactive: 用于处理对象的双向绑定

ref: 用于处理基本类型的双向绑定(但也可以处理对象的双向绑定)

js
setup() {
  const obj1 = reactive({ count:1, name: 'chaos' })
  const obj2 = ref({ count:1, name: 'chaos' })
  setTimeout(() =>{
      obj2.value.count += 1
      obj2.value.name = 'chaos'
  }, 2000)
  return {
    obj1,
    obj2
  }
}

toRefs: 用于将一个 reactive 对象转化为属性全部为ref对象的普通对象

js
<template>
  <div class='homePage'>
    <p>第 {{ year }} 年</p>
    <p>姓名: {{ nickname }}</p>
    <p>年龄: {{ age }}</p>
  </div>
</template>

<script>
import { defineComponent, reactive, ref, toRefs } from 'vue'
export default defineComponent({
  setup() {
    const year = ref(0)
    const user = reactive({ nickname: 'chaos', age: 18, gender: '男' })
    setInterval(() => {
      year.value++
      user.age++
    }, 1000)
    return {
      year,
      // ... user, // 直接解构可以取到值, 但是会丢失响应性
      ...toRefs(user), // 使用reRefs
    }
  },
})
</script>

watch & watchEffect

watch

watch(source, callback, [{options}])

  • source: 用于指定要侦听的响应式变量. 支持string,Object,Function,Array

  • callback: 执行的回调函数

  • options:支持 deep、immediate 和 flush 选项

watch监听ref & reactive定义的对象

js

import {
  defineComponent, reactive, ref, toRefs, watch
} from 'vue'

export default defineComponent({
  setup() {
    const data1 = reactive({ age: 18 })
    const data2 = ref(0)

    setTimeout(() => {
      data1.age += 1
      data2.value += 2
    }, 1000)

    // 监听reactive
    watch(() => data1.age, (curAge, preAge) => {
      console.log('data1新值:', curAge, 'data1老值:', preAge)
    })
    // 监听ref
    watch(data2, (curAge, preAge) => {
      console.log('data2新值:', curAge, 'data2老值:', preAge)
    })
    // 同时监听【返回一个函数,可以停止监听】
    const stopWatch = watch(
      [() => data1.age, data2],
      // 前者是新值构成的array,后者是旧值构成的array
      ([data1NewVal, data2NewVal], [data1OldVal, data2OldVal]) => {
        console.log(data1NewVal, data1OldVal)
        console.log(data2NewVal, data2OldVal)
      },
      {
        deep: true, // 深度监听对象属性
        immediate: true // 初次监听
        // flush: // 暂未搞明白作用
      }
    )
    stopWatch() // 调用后停止监听对应的侦听器(上面由于immediate属性会执行一次,然后立即停止监听,后面数据变更也不会执行了)

    return {
      ...toRefs(data1)
    }
  }
})

watchEffect

  • watchEffect会立即执行传入的函数,并响应式追踪其依赖,并在其依赖变更时重新运行该函数
js
import { defineComponent, ref, reactive, watchEffect } from 'vue'

export default defineComponent({
  setup() {
    const state = reactive({ nickname: 'xiaofan', age: 20 })
    let year = ref(0)
    setInterval(() => {
      state.age++
      year.value++
    }, 1000)
    // 自动收集里面的响应式对象然后监听
    watchEffect(() => {
      console.log(state.age)
      console.log(year.value)
    })
  }
})

computed

与vue2中用法类似

js
import { defineComponent, ref, computed } from 'vue'

export default defineComponent({
  setup() {
    // 一般用法
    const count = ref(1)
    const plusOne = computed(() => count.value + 1)
    console.log(plusOne.value) // 2

    // get/set用法
    const count2 = ref(10)
    const plusOne2 = computed({
      get: () => {
        console.log('get:', count2.value)
        return count2.value + 1
      },
      set: (val) => {
        console.log('set:', val)
        count2.value = val - 1
      }
    })

    plusOne2.value = 1
    console.log(plusOne2.value) // 1
  }
})

生命周期

vue2 与 vue3生命周期对比

image

注意

  • 由于更贴近语义化,beforeDestroy变更成beforeUnmount; destroyed变更为unmounted

  • 同一阶段的钩子,在setup中的钩子优先与options里的调用.

  • 新增钩子函数onRenderTriggeredonRenderTricked用于调试代码

js
import {
  defineComponent, onBeforeMount, onMounted, onRenderTriggered, reactive
} from 'vue'

export default defineComponent({
  mounted() {
    console.log('mounted') // 3
  },
  setup() {
    onMounted(() => {
      console.log('------onMounted-----') // 2
    })
    onBeforeMount(() => {
      console.log('------onBeforeMount-----') // 1
    })
    onRenderTriggered((e) => {
      console.log('------onRenderTriggered-----: ', e) // test.a每次变化event都会被打印(如果没有return test就不会打印任何东西...)
    })

    const test = reactive({ a: 1 })
    setInterval(() => {
      test.a += 2
    }, 1000)
    return {
      test
    }
  }
})