feat(reactivity): new effectScope API (#2195)

This commit is contained in:
Anthony Fu
2021-07-07 21:07:19 +08:00
committed by Evan You
parent 87f69fd0bb
commit f5617fc3bb
16 changed files with 400 additions and 89 deletions

View File

@@ -1,10 +1,10 @@
import { VNode, VNodeChild, isVNode } from './vnode'
import {
ReactiveEffect,
pauseTracking,
resetTracking,
shallowReadonly,
proxyRefs,
EffectScope,
markRaw
} from '@vue/reactivity'
import {
@@ -217,11 +217,6 @@ export interface ComponentInternalInstance {
* Root vnode of this component's own vdom tree
*/
subTree: VNode
/**
* Main update effect
* @internal
*/
effect: ReactiveEffect
/**
* Bound effect runner to be passed to schedulers
*/
@@ -246,7 +241,7 @@ export interface ComponentInternalInstance {
* so that they can be automatically stopped on component unmount
* @internal
*/
effects: ReactiveEffect[] | null
scope: EffectScope
/**
* cache for proxy access type to avoid hasOwnProperty calls
* @internal
@@ -451,14 +446,13 @@ export function createComponentInstance(
root: null!, // to be immediately set
next: null,
subTree: null!, // will be set synchronously right after creation
effect: null!, // will be set synchronously right after creation
update: null!, // will be set synchronously right after creation
scope: new EffectScope(),
render: null,
proxy: null,
exposed: null,
exposeProxy: null,
withProxy: null,
effects: null,
provides: parent ? parent.provides : Object.create(appContext.provides),
accessCache: null!,
renderCache: [],
@@ -533,10 +527,14 @@ export let currentInstance: ComponentInternalInstance | null = null
export const getCurrentInstance: () => ComponentInternalInstance | null = () =>
currentInstance || currentRenderingInstance
export const setCurrentInstance = (
instance: ComponentInternalInstance | null
) => {
export const setCurrentInstance = (instance: ComponentInternalInstance) => {
currentInstance = instance
instance.scope.on()
}
export const unsetCurrentInstance = () => {
currentInstance && currentInstance.scope.off()
currentInstance = null
}
const isBuiltInTag = /*#__PURE__*/ makeMap('slot,component')
@@ -618,7 +616,7 @@ function setupStatefulComponent(
const setupContext = (instance.setupContext =
setup.length > 1 ? createSetupContext(instance) : null)
currentInstance = instance
setCurrentInstance(instance)
pauseTracking()
const setupResult = callWithErrorHandling(
setup,
@@ -627,13 +625,10 @@ function setupStatefulComponent(
[__DEV__ ? shallowReadonly(instance.props) : instance.props, setupContext]
)
resetTracking()
currentInstance = null
unsetCurrentInstance()
if (isPromise(setupResult)) {
const unsetInstance = () => {
currentInstance = null
}
setupResult.then(unsetInstance, unsetInstance)
setupResult.then(unsetCurrentInstance, unsetCurrentInstance)
if (isSSR) {
// return the promise so server-renderer can wait on it
@@ -801,11 +796,11 @@ export function finishComponentSetup(
// support for 2.x options
if (__FEATURE_OPTIONS_API__ && !(__COMPAT__ && skipOptions)) {
currentInstance = instance
setCurrentInstance(instance)
pauseTracking()
applyOptions(instance)
resetTracking()
currentInstance = null
unsetCurrentInstance()
}
// warn missing template/render
@@ -900,17 +895,6 @@ export function getExposeProxy(instance: ComponentInternalInstance) {
}
}
// record effects created during a component's setup() so that they can be
// stopped when the component unmounts
export function recordInstanceBoundEffect(
effect: ReactiveEffect,
instance = currentInstance
) {
if (instance) {
;(instance.effects || (instance.effects = [])).push(effect)
}
}
const classifyRE = /(?:^|[-_])(\w)/g
const classify = (str: string): string =>
str.replace(classifyRE, c => c.toUpperCase()).replace(/[-_]/g, '')