renderToString,
ref,
defineComponent,
- createApp
+ createApp,
+ computed
} from '@vue/runtime-test'
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() {
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 {
NOOP,
isPromise
} from '@vue/shared'
-import { computed } from '@vue/reactivity'
+import { computed, isRef, Ref } from '@vue/reactivity'
import {
watch,
WatchOptions,
// - 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),
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 {
+ 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] = inject(opt)
+ ctx[key] = injected
}
if (__DEV__) {
checkDuplicateProperties!(OptionTypes.INJECT, key)