mirror of https://github.com/vuejs/core.git
feat(app): app.runWithContext() (#7451)
This commit is contained in:
parent
2a9e379655
commit
869f3fb93e
|
@ -110,6 +110,22 @@ describe('api: createApp', () => {
|
||||||
expect(`App already provides property with key "bar".`).toHaveBeenWarned()
|
expect(`App already provides property with key "bar".`).toHaveBeenWarned()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('runWithContext', () => {
|
||||||
|
const app = createApp({
|
||||||
|
setup() {
|
||||||
|
provide('foo', 'should not be seen')
|
||||||
|
return () => h('div')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
app.provide('foo', 1)
|
||||||
|
|
||||||
|
expect(app.runWithContext(() => inject('foo'))).toBe(1)
|
||||||
|
|
||||||
|
// ensure the context is restored
|
||||||
|
inject('foo')
|
||||||
|
expect('inject() can only be used inside setup').toHaveBeenWarned()
|
||||||
|
})
|
||||||
|
|
||||||
test('component', () => {
|
test('component', () => {
|
||||||
const Root = {
|
const Root = {
|
||||||
// local override
|
// local override
|
||||||
|
|
|
@ -51,6 +51,14 @@ export interface App<HostElement = any> {
|
||||||
unmount(): void
|
unmount(): void
|
||||||
provide<T>(key: InjectionKey<T> | string, value: T): this
|
provide<T>(key: InjectionKey<T> | string, value: T): this
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs a function with the app as active instance. This allows using of `inject()` within the function to get access
|
||||||
|
* to variables provided via `app.provide()`.
|
||||||
|
*
|
||||||
|
* @param fn - function to run with the app as active instance
|
||||||
|
*/
|
||||||
|
runWithContext<T>(fn: () => T): T
|
||||||
|
|
||||||
// internal, but we need to expose these for the server-renderer and devtools
|
// internal, but we need to expose these for the server-renderer and devtools
|
||||||
_uid: number
|
_uid: number
|
||||||
_component: ConcreteComponent
|
_component: ConcreteComponent
|
||||||
|
@ -370,6 +378,15 @@ export function createAppAPI<HostElement>(
|
||||||
context.provides[key as string | symbol] = value
|
context.provides[key as string | symbol] = value
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
},
|
||||||
|
|
||||||
|
runWithContext(fn) {
|
||||||
|
currentApp = app
|
||||||
|
try {
|
||||||
|
return fn()
|
||||||
|
} finally {
|
||||||
|
currentApp = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -380,3 +397,9 @@ export function createAppAPI<HostElement>(
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal Used to identify the current app when using `inject()` within
|
||||||
|
* `app.runWithContext()`.
|
||||||
|
*/
|
||||||
|
export let currentApp: App<unknown> | null = null
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { isFunction } from '@vue/shared'
|
import { isFunction } from '@vue/shared'
|
||||||
import { currentInstance } from './component'
|
import { currentInstance } from './component'
|
||||||
import { currentRenderingInstance } from './componentRenderContext'
|
import { currentRenderingInstance } from './componentRenderContext'
|
||||||
|
import { currentApp } from './apiCreateApp'
|
||||||
import { warn } from './warning'
|
import { warn } from './warning'
|
||||||
|
|
||||||
export interface InjectionKey<T> extends Symbol {}
|
export interface InjectionKey<T> extends Symbol {}
|
||||||
|
@ -46,21 +47,24 @@ export function inject(
|
||||||
// fallback to `currentRenderingInstance` so that this can be called in
|
// fallback to `currentRenderingInstance` so that this can be called in
|
||||||
// a functional component
|
// a functional component
|
||||||
const instance = currentInstance || currentRenderingInstance
|
const instance = currentInstance || currentRenderingInstance
|
||||||
if (instance) {
|
|
||||||
|
// also support looking up from app-level provides w/ `app.runWithContext()`
|
||||||
|
if (instance || currentApp) {
|
||||||
// #2400
|
// #2400
|
||||||
// to support `app.use` plugins,
|
// to support `app.use` plugins,
|
||||||
// fallback to appContext's `provides` if the instance is at root
|
// fallback to appContext's `provides` if the instance is at root
|
||||||
const provides =
|
const provides = instance
|
||||||
instance.parent == null
|
? instance.parent == null
|
||||||
? instance.vnode.appContext && instance.vnode.appContext.provides
|
? instance.vnode.appContext && instance.vnode.appContext.provides
|
||||||
: instance.parent.provides
|
: instance.parent.provides
|
||||||
|
: currentApp!._context.provides
|
||||||
|
|
||||||
if (provides && (key as string | symbol) in provides) {
|
if (provides && (key as string | symbol) in provides) {
|
||||||
// TS doesn't allow symbol as index type
|
// TS doesn't allow symbol as index type
|
||||||
return provides[key as string]
|
return provides[key as string]
|
||||||
} else if (arguments.length > 1) {
|
} else if (arguments.length > 1) {
|
||||||
return treatDefaultAsFactory && isFunction(defaultValue)
|
return treatDefaultAsFactory && isFunction(defaultValue)
|
||||||
? defaultValue.call(instance.proxy)
|
? defaultValue.call(instance && instance.proxy)
|
||||||
: defaultValue
|
: defaultValue
|
||||||
} else if (__DEV__) {
|
} else if (__DEV__) {
|
||||||
warn(`injection "${String(key)}" not found.`)
|
warn(`injection "${String(key)}" not found.`)
|
||||||
|
|
Loading…
Reference in New Issue