持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第18天,点击查看活动详情
前言
上一节我们讲了 Setup 的使用以及介绍,并了解了 setup 的处理源码,知道了在什么时候进行调用,今天我们讲讲 setup方法的结果 setupResult 如何进行处理。
handleSetupResult
// packages/runtime-core/src/component.ts
function setupStatefulComponent(
instance: ComponentInternalInstance,
isSSR: boolean
) {
/** 省略代码 */
if (isPromise(setupResult)) {
setupResult.then(unsetCurrentInstance, unsetCurrentInstance)
if (isSSR) {
// return the promise so server-renderer can wait on it
return setupResult
.then((resolvedResult: unknown) => {
handleSetupResult(instance, resolvedResult, isSSR)
})
.catch(e => {
handleError(e, instance, ErrorCodes.SETUP_FUNCTION)
})
} else if (__DEV__) {
warn(
`setup() returned a Promise, but the version of Vue you are using ` +
`does not support it yet.`
)
}
} else {
handleSetupResult(instance, setupResult, isSSR)
}
}
拿到 setup 函数的结果 setupResult 后,会进行分析,并分别做处理。
- 首先判断
setupResult是否为 promise,如果是先会执行 setupResult 并执行unsetCurrentInstance这个方法中把 currentInstance 设置为空。然后判断是否是服务端渲染,如果是则执行setupResult并把结果传给handleSetupResult否则会报错setup() returned a Promise, but the version of Vue you are using does not support it yet.意思就是 setup 返回 promise,当前还不被满足。所以我们在写代码时候,要避免返回 promise。 - 如果不是 promise 则直接调用
handleSetupResult
// packages/runtime-core/src/component.ts
export function handleSetupResult(
instance: ComponentInternalInstance,
setupResult: unknown,
isSSR: boolean
) {
if (isFunction(setupResult)) {
// setup returned an inline render function
if (__SSR__ && (instance.type as ComponentOptions).__ssrInlineRender) {
// when the function's name is `ssrRender` (compiled by SFC inline mode),
// set it as ssrRender instead.
instance.ssrRender = setupResult
} else {
instance.render = setupResult as InternalRenderFunction
}
} else if (isObject(setupResult)) {
instance.setupState = proxyRefs(setupResult)
} else if (__DEV__ && setupResult !== undefined) {
warn(
`setup() should return an object. Received: ${
setupResult === null ? 'null' : typeof setupResult
}`
)
}
finishComponentSetup(instance, isSSR)
}
- 在
handleSetupResult中判断setupResult是否为函数,如果是,会把这个函数当作 渲染render 方法,赋值给 instance.render。 - 如果
setupResult为对象,则调用proxyRefs并传入 setupResult。我们来看看proxyRefs的实现。
// packages/reactivity/src/ref.ts
export function proxyRefs<T extends object>(
objectWithRefs: T
): ShallowUnwrapRef<T> {
return isReactive(objectWithRefs)
? objectWithRefs
: new Proxy(objectWithRefs, shallowUnwrapHandlers)
}
可以看到,如果 setupResult 已经是响应式对象,则直接方法,否则调用 new Proxy 进行代理,转成响应式对象。
- 如果不为函数也不为对象,则会报出警告,
setup 应该返回一个对象或方法。
总结
我们通过两篇分析了 setup 的使用和源码,通过了解源码,我们知道了在写 setup 代码的时候如何提高性能,比如 context没使用时,不要写在形参上 等等。