setup中的内容到底是什么时候执行的

前言

这是vue3系列源码的第四章,使用的vue3版本是3.2.45

推荐

createApp都发生了什么

mount都发生了什么

页面到底是从什么时候开始渲染的

背景

在上一篇文章里,我们探索了vue3的源码中,加载页面部分的源码。纯纯的页面,没有涉及到js代码,那么我们今天想看看,js代码到底是什么时候执行的。

我们今天说的js代码不包括各个周期钩子和副作用函数,只是纯纯的js代码。

前置

我们来看一下我们这次的App.vue组件长什么样子。

js 复制代码
<template>
  <div>{{ aa }}</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'

const aa = ref(11)
console.log('setup', aa.value)
onMounted(() => {
  console.log('onMounted',aa.value)
})
</script>

这里我们只看js部分,其实div是不需要的,不影响。

下面我们就来看看到底会在源码执行的哪一步,打印我们的内容。

在上一篇mount都发生了什么文章中的mountComponent函数中,我们提到过setupComponent这个函数,当时我们没有详细的去说,那么今天,我们讲深入的去了解这个函数。

setupComponent

js 复制代码
function setupComponent(
  instance: ComponentInternalInstance,
  isSSR = false
) {
  isInSSRComponentSetup = isSSR

  const { props, children } = instance.vnode
  const isStateful = isStatefulComponent(instance)
  initProps(instance, props, isStateful, isSSR)
  initSlots(instance, children)

  const setupResult = isStateful
    ? setupStatefulComponent(instance, isSSR)
    : undefined
  isInSSRComponentSetup = false
  return setupResult
}

这里的参数很简单,就是组件的实例。

整个函数看似内容不多。我们可以一个一个看下去。

首先是isStateful,这里其实就是一个与的运算,最终得到的是4,在下面的判断中代表true。

接着是initPropsinitSlots,但是我们这里并没有。而且也不是我们这一章的重点。我们将在后面的章节专门深入。

最后到了setupStatefulComponent,前面都不是重点,那么他就是绝对的重点。

setupStatefulComponent

js 复制代码
function setupStatefulComponent(
  instance: ComponentInternalInstance,
  isSSR: boolean
) {
  const Component = instance.type as ComponentOptions
  // 0. create render proxy property access cache
  instance.accessCache = Object.create(null)
  // 1. create public instance / render proxy
  // also mark it raw so it's never observed
  instance.proxy = markRaw(new Proxy(instance.ctx, PublicInstanceProxyHandlers))
  
  // 2. call setup()
  const { setup } = Component
  if (setup) {
    const setupContext = (instance.setupContext =
      setup.length > 1 ? createSetupContext(instance) : null)

    setCurrentInstance(instance)
    pauseTracking()
    const setupResult = callWithErrorHandling(
      setup,
      instance,
      ErrorCodes.SETUP_FUNCTION,
      [__DEV__ ? shallowReadonly(instance.props) : instance.props, setupContext]
    )
    resetTracking()
    unsetCurrentInstance()

    if (isPromise(setupResult)) {
        ...
    } else {
        handleSetupResult(instance, setupResult, isSSR)
    }
  } else {
    ...
  }
}

参数还是组件的实例。

这段代码的重点在:

  • callWithErrorHandling(setup, instance...),就是在这里,我们的setup的代码执行了。
  • handleSetupResult

setup

我们先看一下setup的执行。

回顾我们的代码段:

js 复制代码
import { ref, onMounted } from 'vue'

const aa = ref(11)
console.log('setup', aa.value)
onMounted(() => {
  console.log('onMounted',aa.value)
})

在setup的执行里,进行了以下步骤:

  • 调用了ref函数创建了ref对象aa
  • 执行到console.log('setup', aa.value),触发了aa对象的get
  • 执行了打印操作,就是在这里,打印了setup 11
  • 调用了createHook函数,向该组件的onMounted钩子注入定义的函数

由此可见,我们setup中的内容其实就是在这里执行了。定义变量和console以及一般的js代码都会在这里得到执行。

我们还发现了,定义在钩子里面的代码,也就是传给钩子的回调函数也是在这里进行了注册,然后等待相应的时机再执行。

这里加了console.log('onMounted',aa.value)纯粹是为了和console.log('setup', aa.value)执行上的不同,关于钩子函数的执行,不在本章讨论,我们将会在后面,详细看看钩子回调函数的执行。

这里其实还涉及到了ref,我们也将会在后面的章节里面进行分析。

handleSetupResult

js 复制代码
function handleSetupResult(
  instance: ComponentInternalInstance,
  setupResult: unknown,
  isSSR: boolean
) {
  if (isFunction(setupResult)) {
    ...
  } else if (isObject(setupResult)) {
    instance.setupState = proxyRefs(setupResult)
  } else if (__DEV__ && setupResult !== undefined) {
   ...
  }
  finishComponentSetup(instance, isSSR)
}

我们先看一下参数:

  • instance,组件实例
  • setupResult, 就是上一步setup执行的结果,是一个对象,具体的内容见下图

这个函数其实和标题setup内容的执行关系不太大了,因为我们想要的已经知道了,这里只是顺带提一下proxyRefs

通过proxyRefs方法对setupResult对象进行了代理,这样我们在组件template中访问aa的时候就不用写aa.value了,而是直接写aa就可以了。

总结

我们虽然只探索了setup的执行,但是其实也顺带着了解了一下ref和生命周期钩子。

从这章开始,我们将逐渐的去了解vue3的那些API。

相关推荐
写代码的小王吧8 分钟前
【安全】Web渗透测试(全流程)_渗透测试学习流程图
linux·前端·网络·学习·安全·网络安全·ssh
小小小小宇35 分钟前
CSS 渐变色
前端
snow@li1 小时前
前端:开源软件镜像站 / 清华大学开源软件镜像站 / 阿里云 / 网易 / 搜狐
前端·开源软件镜像站
小小小小宇2 小时前
配置 Gemini Code Assist 插件
前端
one 大白(●—●)2 小时前
前端用用jsonp的方式解决跨域问题
前端·jsonp跨域
刺客-Andy2 小时前
前端加密方式 AES对称加密 RSA非对称加密 以及 MD5哈希算法详解
前端·javascript·算法·哈希算法
前端开发张小七2 小时前
13.Python Socket服务端开发指南
前端·python
前端开发张小七2 小时前
14.Python Socket客户端开发指南
前端·python
ElasticPDF-新国产PDF编辑器3 小时前
Vue 项目 PDF 批注插件库在线版 API 示例教程
前端·vue.js·pdf
拉不动的猪3 小时前
react基础2
前端·javascript·面试