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。

相关推荐
王哲晓2 分钟前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
fg_4115 分钟前
无网络安装ionic和运行
前端·npm
理想不理想v7 分钟前
‌Vue 3相比Vue 2的主要改进‌?
前端·javascript·vue.js·面试
酷酷的阿云17 分钟前
不用ECharts!从0到1徒手撸一个Vue3柱状图
前端·javascript·vue.js
微信:1379712058719 分钟前
web端手机录音
前端
齐 飞25 分钟前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
神仙别闹42 分钟前
基于tensorflow和flask的本地图片库web图片搜索引擎
前端·flask·tensorflow
GIS程序媛—椰子2 小时前
【Vue 全家桶】7、Vue UI组件库(更新中)
前端·vue.js
DogEgg_0012 小时前
前端八股文(一)HTML 持续更新中。。。
前端·html
ZL不懂前端2 小时前
Content Security Policy (CSP)
前端·javascript·面试