parent
8681c12c0c
commit
561e210157
@ -9,7 +9,8 @@ import {
|
|||||||
renderToString,
|
renderToString,
|
||||||
ref,
|
ref,
|
||||||
defineComponent,
|
defineComponent,
|
||||||
createApp
|
createApp,
|
||||||
|
computed
|
||||||
} from '@vue/runtime-test'
|
} from '@vue/runtime-test'
|
||||||
|
|
||||||
describe('api: options', () => {
|
describe('api: options', () => {
|
||||||
@ -426,6 +427,69 @@ describe('api: options', () => {
|
|||||||
expect(renderToString(h(Root))).toBe(`1111234522`)
|
expect(renderToString(h(Root))).toBe(`1111234522`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('provide/inject refs', async () => {
|
||||||
|
const n = ref(0)
|
||||||
|
const np = computed(() => n.value + 1)
|
||||||
|
const Parent = defineComponent({
|
||||||
|
provide() {
|
||||||
|
return {
|
||||||
|
n,
|
||||||
|
np
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render: () => h(Child)
|
||||||
|
})
|
||||||
|
const Child = defineComponent({
|
||||||
|
inject: ['n', 'np'],
|
||||||
|
render(this: any) {
|
||||||
|
return this.n + this.np
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const app = createApp(Parent)
|
||||||
|
// TODO remove in 3.3
|
||||||
|
app.config.unwrapInjectedRef = true
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
app.mount(root)
|
||||||
|
expect(serializeInner(root)).toBe(`1`)
|
||||||
|
|
||||||
|
n.value++
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe(`3`)
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO remove in 3.3
|
||||||
|
test('provide/inject refs (compat)', async () => {
|
||||||
|
const n = ref(0)
|
||||||
|
const np = computed(() => n.value + 1)
|
||||||
|
const Parent = defineComponent({
|
||||||
|
provide() {
|
||||||
|
return {
|
||||||
|
n,
|
||||||
|
np
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render: () => h(Child)
|
||||||
|
})
|
||||||
|
const Child = defineComponent({
|
||||||
|
inject: ['n', 'np'],
|
||||||
|
render(this: any) {
|
||||||
|
return this.n.value + this.np.value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const app = createApp(Parent)
|
||||||
|
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
app.mount(root)
|
||||||
|
expect(serializeInner(root)).toBe(`1`)
|
||||||
|
|
||||||
|
n.value++
|
||||||
|
await nextTick()
|
||||||
|
expect(serializeInner(root)).toBe(`3`)
|
||||||
|
|
||||||
|
expect(`injected property "n" is a ref`).toHaveBeenWarned()
|
||||||
|
expect(`injected property "np" is a ref`).toHaveBeenWarned()
|
||||||
|
})
|
||||||
|
|
||||||
test('provide accessing data in extends', () => {
|
test('provide accessing data in extends', () => {
|
||||||
const Base = defineComponent({
|
const Base = defineComponent({
|
||||||
data() {
|
data() {
|
||||||
|
@ -81,16 +81,22 @@ export interface AppConfig {
|
|||||||
trace: string
|
trace: string
|
||||||
) => void
|
) => void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options to pass to @vue/compiler-dom.
|
||||||
|
* Only supported in runtime compiler build.
|
||||||
|
*/
|
||||||
|
compilerOptions: RuntimeCompilerOptions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated use config.compilerOptions.isCustomElement
|
* @deprecated use config.compilerOptions.isCustomElement
|
||||||
*/
|
*/
|
||||||
isCustomElement?: (tag: string) => boolean
|
isCustomElement?: (tag: string) => boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options to pass to @vue/compiler-dom.
|
* Temporary config for opt-in to unwrap injected refs.
|
||||||
* Only supported in runtime compiler build.
|
* TODO deprecate in 3.3
|
||||||
*/
|
*/
|
||||||
compilerOptions: RuntimeCompilerOptions
|
unwrapInjectedRef?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AppContext {
|
export interface AppContext {
|
||||||
|
@ -17,7 +17,7 @@ import {
|
|||||||
NOOP,
|
NOOP,
|
||||||
isPromise
|
isPromise
|
||||||
} from '@vue/shared'
|
} from '@vue/shared'
|
||||||
import { computed } from '@vue/reactivity'
|
import { computed, isRef, Ref } from '@vue/reactivity'
|
||||||
import {
|
import {
|
||||||
watch,
|
watch,
|
||||||
WatchOptions,
|
WatchOptions,
|
||||||
@ -607,15 +607,21 @@ export function applyOptions(instance: ComponentInternalInstance) {
|
|||||||
// - watch (deferred since it relies on `this` access)
|
// - watch (deferred since it relies on `this` access)
|
||||||
|
|
||||||
if (injectOptions) {
|
if (injectOptions) {
|
||||||
resolveInjections(injectOptions, ctx, checkDuplicateProperties)
|
resolveInjections(
|
||||||
|
injectOptions,
|
||||||
|
ctx,
|
||||||
|
checkDuplicateProperties,
|
||||||
|
instance.appContext.config.unwrapInjectedRef
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (methods) {
|
if (methods) {
|
||||||
for (const key in methods) {
|
for (const key in methods) {
|
||||||
const methodHandler = (methods as MethodOptions)[key]
|
const methodHandler = (methods as MethodOptions)[key]
|
||||||
if (isFunction(methodHandler)) {
|
if (isFunction(methodHandler)) {
|
||||||
// In dev mode, we use the `createRenderContext` function to define methods to the proxy target,
|
// In dev mode, we use the `createRenderContext` function to define
|
||||||
// and those are read-only but reconfigurable, so it needs to be redefined here
|
// methods to the proxy target, and those are read-only but
|
||||||
|
// reconfigurable, so it needs to be redefined here
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
Object.defineProperty(ctx, key, {
|
Object.defineProperty(ctx, key, {
|
||||||
value: methodHandler.bind(publicThis),
|
value: methodHandler.bind(publicThis),
|
||||||
@ -810,25 +816,51 @@ export function applyOptions(instance: ComponentInternalInstance) {
|
|||||||
export function resolveInjections(
|
export function resolveInjections(
|
||||||
injectOptions: ComponentInjectOptions,
|
injectOptions: ComponentInjectOptions,
|
||||||
ctx: any,
|
ctx: any,
|
||||||
checkDuplicateProperties = NOOP as any
|
checkDuplicateProperties = NOOP as any,
|
||||||
|
unwrapRef = false
|
||||||
) {
|
) {
|
||||||
if (isArray(injectOptions)) {
|
if (isArray(injectOptions)) {
|
||||||
injectOptions = normalizeInject(injectOptions)!
|
injectOptions = normalizeInject(injectOptions)!
|
||||||
}
|
}
|
||||||
for (const key in injectOptions) {
|
for (const key in injectOptions) {
|
||||||
const opt = (injectOptions as ObjectInjectOptions)[key]
|
const opt = (injectOptions as ObjectInjectOptions)[key]
|
||||||
|
let injected: unknown
|
||||||
if (isObject(opt)) {
|
if (isObject(opt)) {
|
||||||
if ('default' in opt) {
|
if ('default' in opt) {
|
||||||
ctx[key] = inject(
|
injected = inject(
|
||||||
opt.from || key,
|
opt.from || key,
|
||||||
opt.default,
|
opt.default,
|
||||||
true /* treat default function as factory */
|
true /* treat default function as factory */
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
ctx[key] = inject(opt.from || key)
|
injected = inject(opt.from || key)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ctx[key] = inject(opt)
|
injected = inject(opt)
|
||||||
|
}
|
||||||
|
if (isRef(injected)) {
|
||||||
|
// TODO remove the check in 3.3
|
||||||
|
if (unwrapRef) {
|
||||||
|
Object.defineProperty(ctx, key, {
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true,
|
||||||
|
get: () => (injected as Ref).value,
|
||||||
|
set: v => ((injected as Ref).value = v)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if (__DEV__) {
|
||||||
|
warn(
|
||||||
|
`injected property "${key}" is a ref and will be auto-unwrapped ` +
|
||||||
|
`and no longer needs \`.value\` in the next minor release. ` +
|
||||||
|
`To opt-in to the new behavior now, ` +
|
||||||
|
`set \`app.config.unwrapInjectedRef = true\` (this config is ` +
|
||||||
|
`temporary and will not be needed in the future.)`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ctx[key] = injected
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctx[key] = injected
|
||||||
}
|
}
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
checkDuplicateProperties!(OptionTypes.INJECT, key)
|
checkDuplicateProperties!(OptionTypes.INJECT, key)
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
defineCustomElement,
|
defineCustomElement,
|
||||||
h,
|
h,
|
||||||
|
inject,
|
||||||
nextTick,
|
nextTick,
|
||||||
|
Ref,
|
||||||
ref,
|
ref,
|
||||||
renderSlot,
|
renderSlot,
|
||||||
VueElement
|
VueElement
|
||||||
@ -231,9 +233,9 @@ describe('defineCustomElement', () => {
|
|||||||
|
|
||||||
describe('provide/inject', () => {
|
describe('provide/inject', () => {
|
||||||
const Consumer = defineCustomElement({
|
const Consumer = defineCustomElement({
|
||||||
inject: ['foo'],
|
setup() {
|
||||||
render(this: any) {
|
const foo = inject<Ref>('foo')!
|
||||||
return h('div', this.foo.value)
|
return () => h('div', foo.value)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
customElements.define('my-consumer', Consumer)
|
customElements.define('my-consumer', Consumer)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user