程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

Vue3源码 第四篇-Vue3 setup

发布于2021-10-19 22:46     阅读(1142)     评论(0)     点赞(27)     收藏(5)


系列文章目录

Vue3源码 第一篇-总览
Vue3源码 第二篇-Reactive API
Vue3源码 第三篇-Vue3是如何实现响应性

前言

setup作为Vue3的组合式API的重要特性,改变了之前OptionAPI的写代码方式,setup函数让Vue3对逻辑的封装更为简单,那么他又是在Vue3上如何挂载,如何访问的呢?我们接下来一起阅读源码,从源码中深入了解setup函数。话不多说,直接开冲!!!
在这里插入图片描述

一、源码阅读

1.setup函数的创建

要找到setup的挂载,第一步找到在哪里执行setup函数,我们知道setup函数肯定在组件挂载的时候执行,所以我们在组件挂载的代码中找到了setupStatefulComponent函数,该函数中包含了组件各个部分的挂载,自然也包含了setup函数的挂载,我们来阅读下这个函数中setup函数相关的代码。

function setupStatefulComponent(instance, isSSR) {
    // ...省略其他代码
    // 2. call setup() 组件中存在setup函数,挂载过程中,最先开始挂载的就是setup函数,之后才是optionApi的挂载
    const { setup } = Component;
    if (setup) {
    	// 创建setup函数的上下文
        const setupContext = (instance.setupContext =
            setup.length > 1 ? createSetupContext(instance) : null);
        currentInstance = instance;
        pauseTracking();
        // 获取setup结果,外层包裹函数错误处理函数callWithErrorHandling
        const setupResult = callWithErrorHandling(setup, instance, 0 /* SETUP_FUNCTION */, [shallowReadonly(instance.props) , setupContext]);
        resetTracking();
        currentInstance = null;
        // 对不同的结果进行处理
        // 如果结果是promise
        if (isPromise(setupResult)) {
            if (isSSR) { // 当前是SSR 服务器端渲染
                // return the promise so server-renderer can wait on it
                return setupResult
                    .then((resolvedResult) => {// 等待服务器返回结果在进行处理
                        handleSetupResult(instance, resolvedResult, isSSR);
                    })
                    .catch(e => {
                        handleError(e, instance, 0 /* SETUP_FUNCTION */);
                    });
            }
            else {
                // async setup returned Promise. 如果只是单纯的异步,就直接赋值暂时跳过
                // bail here and wait for re-entry.
                instance.asyncDep = setupResult;
            }
        }
        else {// 如果不是promise,直接处理返回结果
            handleSetupResult(instance, setupResult, isSSR);
        }
    }
    else {
    	// 如果不存在setup函数就直接进行下面optionApi的挂载,
    	// 不包括props的执行,在Vue3中,props最先执行,之后是setup,最后是其他optionAPI
        finishComponentSetup(instance, isSSR);
    }
}

我们先整体的了解的setup的挂载过程,接下来我们仔细将setup函数挂载分为:setup函数上下文的创建,setup的执行,setup返回的处理3个具体步骤来仔细阅读其中的代码。

1.1 setup函数上下文(context)创建

createSetupContext函数创建setup函数的上下文,包含了一些在setup函数中可能会用到的属性和方法等。

function createSetupContext(instance) {
   const expose = exposed => {
   		 // exopose函数,当setup返回渲染函数时会用到,因为返回渲染函数时无法暴露其他东西,所以可以通过expose函数暴露
   		 // 具体可以查看官网 https://v3.cn.vuejs.org/guide/composition-api-setup.html#使用渲染函数
         if (instance.exposed) {
             warn(`expose() should be called only once per setup().`);
         }
         instance.exposed = proxyRefs(exposed);
     };
     {
         // We use getters in dev in case libs like test-utils overwrite instance
         // properties (overwrites should not be done in prod)
         return Object.freeze({
             get attrs() { // $attrs 组件上的属性
                 return new Proxy(instance.attrs, attrHandlers);
             },
             get slots() { // $slots 插槽
                 return shallowReadonly(instance.slots);
             },
             get emit() { // $emit 触发事件的方法
                 return (event, ...args) => instance.emit(event, ...args);
             },
             expose
         });
     }
 }

1.2 setup函数执行

callWithErrorHandling方法在Vue2和3版本中都很常见,主要是对执行函数进行错误处理的封装。对执行的函数进行try-catch处理。

const setupResult = callWithErrorHandling(setup, instance, 0 /* SETUP_FUNCTION */, 
											[shallowReadonly(instance.props) , setupContext]);
// 第一个参数是setup函数本身
// 第二个参数是组件实例
// 第三个参数是标志执行函数类型
// 第四个参数是由props和刚才执行的上下文组成的参数
function callWithErrorHandling(fn, instance, type, args) {
    let res;
    try {
        res = args ? fn(...args) : fn();
    }
    catch (err) {
        handleError(err, instance, type);
    }
    return res;
}

通过setup函数的执行代码,我们可以知道,在执行setup函数中,我们能获取到的是props和之前提到的上下文参数,有一点也特别重要,我们在执行setup函数的时候并没有传入instance对象,也就是无法获取实例对象,并且在context中也没有传入data,method等信息(其实这里是因为这些的创建在setup函数之后)所以官网也指出:
你将无法在setup函数中访问以下组件选项:
data
computed
methods
refs (模板 ref)

还有一点setup函数的this,也没有绑定instance,所以setup的this无法获取到vue实例。这样就验证了官网所说的:
在 setup() 内部,this 不是该活跃实例的引用

1.3 setup函数执行结果处理

handleSetupResult处理setup返回结果,将结果绑定到instance上方便其他函数调用

function handleSetupResult(instance, setupResult, isSSR) {
	 // 如果返回的是函数,就是渲染函数,设置实例上的render函数为该函数
     if (isFunction(setupResult)) {
         // setup returned an inline render function
         {
             instance.render = setupResult;
         }
     }
     else if (isObject(setupResult)) { // 返回对象
         if (isVNode(setupResult)) {
             warn(`setup() should not return VNodes directly - ` +
                 `return a render function instead.`);
         }
         // setup returned bindings.
         // assuming a render function compiled from template is present.
         {
             instance.devtoolsRawSetupState = setupResult;
         }
         // 将返回结果转换成reactive对象,并且放入到实例的setupState上
         instance.setupState = proxyRefs(setupResult);
         {
             exposeSetupStateOnRenderContext(instance);
         }
     }
     else if (setupResult !== undefined) {
         warn(`setup() should return an object. Received: ${setupResult === null ? 'null' : typeof setupResult}`);
     }
     finishComponentSetup(instance, isSSR);
 }

总结

今天对setup函数的创建过程进行了源码阅读,包括他的上下文创建,setup函数的执行还有对setup结果的处理,个人理解有限,若有不好的地方希望大家多多斧正,最后拜托大家给个三连吧~~~
在这里插入图片描述

原文链接:https://blog.csdn.net/qq_26626113/article/details/120657470




所属网站分类: 技术文章 > 博客

作者:听说你很拽

链接:http://www.qianduanheidong.com/blog/article/203849/9d41ca4e7a95a8b4c45a/

来源:前端黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

27 0
收藏该文
已收藏

评论内容:(最多支持255个字符)