parent
8681c12c0c
commit
561e210157
@ -9,7 +9,8 @@ import {
|
||||
renderToString,
|
||||
ref,
|
||||
defineComponent,
|
||||
createApp
|
||||
createApp,
|
||||
computed
|
||||
} from '@vue/runtime-test'
|
||||
|
||||
describe('api: options', () => {
|
||||
@ -426,6 +427,69 @@ describe('api: options', () => {
|
||||
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', () => {
|
||||
const Base = defineComponent({
|
||||
data() {
|
||||
|
@ -81,16 +81,22 @@ export interface AppConfig {
|
||||
trace: string
|
||||
) => void
|
||||
|
||||
/**
|
||||
* Options to pass to @vue/compiler-dom.
|
||||
* Only supported in runtime compiler build.
|
||||
*/
|
||||
compilerOptions: RuntimeCompilerOptions
|
||||
|
||||
/**
|
||||
* @deprecated use config.compilerOptions.isCustomElement
|
||||
*/
|
||||
isCustomElement?: (tag: string) => boolean
|
||||
|
||||
/**
|
||||
* Options to pass to @vue/compiler-dom.
|
||||
* Only supported in runtime compiler build.
|
||||
* Temporary config for opt-in to unwrap injected refs.
|
||||
* TODO deprecate in 3.3
|
||||
*/
|
||||
compilerOptions: RuntimeCompilerOptions
|
||||
unwrapInjectedRef?: boolean
|
||||
}
|
||||
|
||||
export interface AppContext {
|
||||
|
@ -17,7 +17,7 @@ import {
|
||||
NOOP,
|
||||
isPromise
|
||||
} from '@vue/shared'
|
||||
import { computed } from '@vue/reactivity'
|
||||
import { computed, isRef, Ref } from '@vue/reactivity'
|
||||
import {
|
||||
watch,
|
||||
WatchOptions,
|
||||
@ -607,15 +607,21 @@ export function applyOptions(instance: ComponentInternalInstance) {
|
||||
// - watch (deferred since it relies on `this` access)
|
||||
|
||||
if (injectOptions) {
|
||||
resolveInjections(injectOptions, ctx, checkDuplicateProperties)
|
||||
resolveInjections(
|
||||
injectOptions,
|
||||
ctx,
|
||||
checkDuplicateProperties,
|
||||
instance.appContext.config.unwrapInjectedRef
|
||||
)
|
||||
}
|
||||
|
||||
if (methods) {
|
||||
for (const key in methods) {
|
||||
const methodHandler = (methods as MethodOptions)[key]
|
||||
if (isFunction(methodHandler)) {
|
||||
// In dev mode, we use the `createRenderContext` function to define methods to the proxy target,
|
||||
// and those are read-only but reconfigurable, so it needs to be redefined here
|
||||
// In dev mode, we use the `createRenderContext` function to define
|
||||
// methods to the proxy target, and those are read-only but
|
||||
// reconfigurable, so it needs to be redefined here
|
||||
if (__DEV__) {
|
||||
Object.defineProperty(ctx, key, {
|
||||
value: methodHandler.bind(publicThis),
|
||||
@ -810,25 +816,51 @@ export function applyOptions(instance: ComponentInternalInstance) {
|
||||
export function resolveInjections(
|
||||
injectOptions: ComponentInjectOptions,
|
||||
ctx: any,
|
||||
checkDuplicateProperties = NOOP as any
|
||||
checkDuplicateProperties = NOOP as any,
|
||||
unwrapRef = false
|
||||
) {
|
||||
if (isArray(injectOptions)) {
|
||||
injectOptions = normalizeInject(injectOptions)!
|
||||
}
|
||||
for (const key in injectOptions) {
|
||||
const opt = (injectOptions as ObjectInjectOptions)[key]
|
||||
let injected: unknown
|
||||
if (isObject(opt)) {
|
||||
if ('default' in opt) {
|
||||
ctx[key] = inject(
|
||||
injected = inject(
|
||||
opt.from || key,
|
||||
opt.default,
|
||||
true /* treat default function as factory */
|
||||
)
|
||||
} else {
|
||||
ctx[key] = inject(opt.from || key)
|
||||
injected = inject(opt.from || key)
|
||||
}
|
||||
} 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__) {
|
||||
checkDuplicateProperties!(OptionTypes.INJECT, key)
|
||||
|
@ -1,7 +1,9 @@
|
||||
import {
|
||||
defineCustomElement,
|
||||
h,
|
||||
inject,
|
||||
nextTick,
|
||||
Ref,
|
||||
ref,
|
||||
renderSlot,
|
||||
VueElement
|
||||
@ -231,9 +233,9 @@ describe('defineCustomElement', () => {
|
||||
|
||||
describe('provide/inject', () => {
|
||||
const Consumer = defineCustomElement({
|
||||
inject: ['foo'],
|
||||
render(this: any) {
|
||||
return h('div', this.foo.value)
|
||||
setup() {
|
||||
const foo = inject<Ref>('foo')!
|
||||
return () => h('div', foo.value)
|
||||
}
|
||||
})
|
||||
customElements.define('my-consumer', Consumer)
|
||||
|
Loading…
Reference in New Issue
Block a user