【Vue.js 3.0源码】Composition API之组件渲染初始化过程(上)

自我介绍:大家好,我是吉帅振的网络日志;微信公众号:吉帅振的网络日志;前端开发工程师,工作4年,去过上海、北京,经历创业公司,进过大厂,现在郑州敲代码。

一、前言:

Vue.js 3.0 设计了一个很强大的 API —— Composition API,它主要用来优化代码逻辑的组织和复用。从语法上看,它提供了一个 setup 启动函数作为逻辑组织的入口,暴露了响应式 API 为用户所用,也提供了生命周期函数以及依赖注入的接口,这让我们不依托于 Options API 也可以完成一个组件的开发,并且更有利于代码逻辑的组织和复用。但是我们要明确一点,Composition API 属于 API 的增强,它并不是 Vue.js 3.0 组件开发的范式,如果你的组件足够简单,你还是可以使用 Options API。

二、初始化

Vue.js 3.0 允许我们在编写组件的时候添加一个 setup 启动函数,它是 Composition API 逻辑组织的入口,我们先通过一段代码认识它,在这里编写一个 button 组件:

<template>

  <button @click="increment">

    Count is: {
  { state.count }}, double is: {
  { state.double }}

  </button>

</template>

<script>

import { reactive, computed } from 'vue'

export default {

  setup() {

    const state = reactive({

      count: 0,

      double: computed(() => state.count * 2)

    })

    function increment() {

      state.count++

    }

    return {

      state,

      increment

    }

  }

}

</script>

可以看到,这段代码和 Vue.js 2.x 组件的写法相比,多了一个 setup 启动函数,另外组件中也没有定义 props、data、computed 这些 options。在 setup 函数内部,定义了一个响应式对象 state,它是通过 reactive API 创建的。state 对象有 count 和 double 两个属性,其中 count 对应一个数字属性的值;而double 通过 computed API 创建,对应一个计算属性的值。reactive API 和 computed API 不是我们关注的重点,在后续响应式章节我会详细介绍。

这里需要注意的是,模板中引用到的变量 state 和 increment 包含在 setup 函数的返回对象中,那么它们是如何建立联系的呢?

我们先来回想一下 Vue.js 2.x 编写组件的时候,会在 props、data、methods、computed 等 options 中定义一些变量。在组件初始化阶段,Vue.js 内部会处理这些 options,即把定义的变量添加到了组件实例上。等模板编译成 render 函数的时候,内部通过 with(this){} 的语法去访问在组件实例中的变量。那么到了 Vue.js 3.0,既支持组件定义 setup 函数,而且在模板 render 的时候,又可以访问到 setup 函数返回的值,这是如何实现的?我们来一探究竟。

创建和设置组件实例

首先,我们来回顾一下组件的渲染流程:创建 vnode 、渲染 vnode 和生成 DOM。其中渲染 vnode 的过程主要就是在挂载组件:

const mountComponent = (initialVNode, container, anchor, parentComponent, parentSuspense, isSVG, optimized) => {

  // 创建组件实例

  const instance = (initialVNode.component = createComponentInstance(initialVNode, parentComponent, parentSuspense))

  // 设置组件实例

  setupComponent(instance)

  // 设置并运行带副作用的渲染函数

  setupRenderEffect(instance, initialVNode, container, anchor, parentSuspense, isSVG, optimized)

}

可以看到,这段挂载组件的代码主要做了三件事情:创建组件实例、设置组件实例和设置并运行带副作用的渲染函数。前两个流程就跟我们今天提到的问题息息相关。

createComponentInstance 方法的实现:

function createComponentInstance (vnode, parent, suspense) {

  // 继承父组件实例上的 appContext,如果是根组件,则直接从根 vnode 中取。

  const appContext = (parent ? parent.appContext : vnode.appContext) || emptyAppContext;

  const instance = {

    // 组件唯一 id

    uid: uid++,

    // 组件 vnode

    vnode,

    // 父组件实例

    parent,

    // app 上下文

    appC
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值