Skip to content
本页目录

【Vue3】Composition API 之 setup

setup 是啥

setup, 一个组件选项,在创建组件之前执行,一旦 props 被解析,并作为组合式 API 的入口点。
入参:

{Data} props
{SetupContext} context

setup 的作用

Composition API 是针对 Vue 框架而言的,而不是对于用户层面的。 他是在 Vue 中,将一系列的 hook 组合起来,向外暴露的 api。比如在 Vue2.x 中,你需要调用mounted生命周期,在 vue3 中,由 Composition API 给我们提供 onMounted hook 来调用。

在 Vue2.x 中,使用的方式叫 Options API。在 Vue3.x 中依然可以使用,但在 Vue3.x 中,更应该使用新的 API。

js
// vue2.x 中的 Option API 方式
export default {
  data() {
    return {
      name: 'kirito'
    }
  },
  computed: {
    upperCaseName(){
      return this.name.toLocaleUpperCase()
    }
  },
  mounted() {
    this.name = 'Naroto'
  },
  watch: {
    name: {
      handler(n, o) {
        // when name is change, do something
      }
    }
  },
}

// vue3.x 中的 Composition API 方式
import { ref, watch, onMounted, computed } from 'vue';

export default {
  setup() {
    const name = ref('kirito');
    const upperCaseName = () => name.toLocaleUpperCase();

    onMounted(() => {
      name.value = 'Naroto';
    })

    watch([name], (ns, os) => {
      // when name is change, do something
    })

    return {
      name,
      upperCaseName,
    }
  }
}

Composition API 中的 setup 方法就是用于组合这一系列的 hook。并且所有 vue 提供的 hook,都只能在这个 setup 函数中起作用

返回值

在 vue3.x 中,没有 data 函数,这里的 setup 方法返回有两种形式,分别为 objectrender function

  • Object(对象) 当返回值是 object 时,那这个返回值将用作 template 的上下文。
html
<template>
  <div>{{ count }}</div>
</template>

<script>
  export default {
    setup() {
      // 返回一个 object
      return {
        count: 0
      }
    }
  }
</script>
  • Render Function (渲染函数) 当然,也可以返回一个渲染函数。常见在 jsx 语法中。
js
import { h, ref, reactive } from 'vue'

export default {
  setup() {
    const readersNumber = ref(0)
    const book = reactive({ title: 'Vue 3 Guide' })
    // 返回一个渲染函数,其中 h 方法由 vue 提供
    return () => h('div', [readersNumber.value, h('h1', [book.title])])
  }
}

调用时机

setup 函数是在初始化属性 props 之后被调用。按照 vue2.x 的生命周期的角度,它将在 beforeCreate 调用之前被调用。值得注意的是,在 Vue3.x 中已经删除了 beforeCreatecreated这两个生命钩子。

js
import { onBeforeMount, onMounted, onBeforeUnmount } from 'vue'

export default {
  setup() {
    console.log('setup')

    // ...
    onBeforeMount(() => console.log('onBeforeMount'))

    onMounted(() => console.log('onMounted'))

    onBeforeUnmount(() => console.log('onBeforeUnmount'))
  }
}

结果按照下面的顺序输出

setup -> onBeforeMount -> onMounted -> onBeforeUnmount

下面是来自官网的生命周期的用法对比:

Option API(vue2.x)Composition API(vue3.x)调用时机
beforeCreate已删除初始化之前
created已删除初始化之后
beforeMountonBeforeMount挂载之前
mountedonMounted挂载之后
beforeUpdateonBeforeUpdate更新之前
updatedonUpdated更新之后
beforeUnmountonBeforeUnmount卸载之前
unmountedonUnmounted卸载之后
errorCapturedonErrorCaptured当捕获一个来自子孙组件的错误时被调用
renderTrackedonRenderTracked在跟踪虚拟 DOM 重新呈现时调用
renderTriggeredonRenderTriggered触发虚拟 DOM 重新呈现时调用

参数

setup 函数中,默认有两个参数,propscontext

props

setup 函数中的第一个参数是 props。正如在一个标准组件中所期望的那样,setup 函数中的 props 是响应式的,当传入新的 prop 时,它将被更新。

js
export default {
  props: {
    title: String
  },
  setup(props) {
    console.log(props.title)
  }
}

但是,因为 props 是响应式 的,你 不能使用 ES6 解构,因为它会消除 prop 的响应性。如果需要解构 prop,可以通过使用 setup 函数中的 toRefs 来安全地完成此操作。也不能在组件中,去直接修改 props

js
import { toRefs } from 'vue'

export default {
  setup(props) {
    const { title } = toRefs(props)
    console.log(title.value)
  }
}

context

传递给 setup 函数的第二个参数是 context。context 是一个普通的 JavaScript 对象,它暴露组件的三个 property

context 是一个普通的 JavaScript 对象,也就是说,它不是响应式的,这意味着你可以安全地对 context 使用 ES6 解构。

js
export default {
  setup(props, context) {
    // Attribute (非响应式对象)
    console.log(context.attrs)

    // 插槽 (非响应式对象)
    console.log(context.slots)

    // 触发事件 (方法)
    console.log(context.emit)

    // 解构
    const { attrs, slots, emit } = context
  }
}

attrsslots 是有状态的对象,它们总是会随组件本身的更新而更新。这意味着你应该避免对它们进行解构,并始终以 attrs.xslots.x 的方式引用 property。请注意,与 props 不同,attrsslots 是非响应式的。如果你打算根据 attrsslots 更改应用副作用,那么应该在 onUpdated 生命周期钩子中执行此操作。

由于 setup 函数的调用时机是在组件的其他选项解析,所以在 setup 中无法使用this的, 因为调用时,组件实例还未创建。 所以Option API中的 datamethodscomputed等,是无法访问的。

vue3.x 也会提供一个 hook, getCurrentInstance 用于获取当前组件的实例。

js
import { getCurrentInstance } from 'vue'

export default {
  setup(props, context) {
    const ctx = getCurrentInstance()

    // context === ctx;
    context.emit('input')
    ctx.emit('input')
  }
}

写在最后

setup 方法作为 vue3.x 的 hook 入口,是学习 vue3.x 的入口,这是十分重要的。(敲黑板、划重点~~)

如有转载或 CV 的请标注本站原文地址