Skip to content

Commit

Permalink
refactor(template-ref): improve template ref handling
Browse files Browse the repository at this point in the history
close #836, close #839
  • Loading branch information
yyx990803 committed Mar 16, 2020
1 parent 8a58dce commit 9ad65b1
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 114 deletions.
49 changes: 0 additions & 49 deletions packages/compiler-core/__tests__/transforms/transformRef.spec.ts

This file was deleted.

2 changes: 0 additions & 2 deletions packages/compiler-core/src/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { transform, NodeTransform, DirectiveTransform } from './transform'
import { generate, CodegenResult } from './codegen'
import { RootNode } from './ast'
import { isString } from '@vue/shared'
import { transformRef } from './transforms/transformRef'
import { transformIf } from './transforms/vIf'
import { transformFor } from './transforms/vFor'
import { transformExpression } from './transforms/transformExpression'
Expand All @@ -28,7 +27,6 @@ export function getBaseTransformPreset(
): TransformPreset {
return [
[
transformRef,
transformOnce,
transformIf,
transformFor,
Expand Down
40 changes: 0 additions & 40 deletions packages/compiler-core/src/transforms/transformRef.ts

This file was deleted.

32 changes: 27 additions & 5 deletions packages/runtime-core/__tests__/apiTemplateRef.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ describe('api: template refs', () => {
}
},
render() {
// Note: string refs are compiled into [ctx, key] tuples by the compiler
// to ensure correct context.
return h('div', { ref: [this, 'refKey'] as any })
return h('div', { ref: 'refKey' })
}
}
render(h(Comp), root)
Expand All @@ -45,7 +43,7 @@ describe('api: template refs', () => {
}
},
render() {
return h('div', { ref: [this, refKey.value] as any })
return h('div', { ref: refKey.value })
}
}
render(h(Comp), root)
Expand All @@ -70,7 +68,7 @@ describe('api: template refs', () => {
}
},
render() {
return toggle.value ? h('div', { ref: [this, 'refKey'] as any }) : null
return toggle.value ? h('div', { ref: 'refKey' }) : null
}
}
render(h(Comp), root)
Expand Down Expand Up @@ -178,4 +176,28 @@ describe('api: template refs', () => {
await nextTick()
expect(el.value).toBe(null)
})

test('string ref inside slots', async () => {
const root = nodeOps.createElement('div')
const spy = jest.fn()
const Child = {
render(this: any) {
return this.$slots.default()
}
}

const Comp = {
render() {
return h(Child, () => {
return h('div', { ref: 'foo' })
})
},
mounted(this: any) {
spy(this.$refs.foo.tag)
}
}
render(h(Comp), root)

expect(spy).toHaveBeenCalledWith('div')
})
})
30 changes: 15 additions & 15 deletions packages/runtime-core/src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
VNodeArrayChildren,
createVNode,
isSameVNodeType,
Static
Static,
VNodeNormalizedRef
} from './vnode'
import {
ComponentInternalInstance,
Expand All @@ -30,8 +31,7 @@ import {
isFunction,
PatchFlags,
ShapeFlags,
NOOP,
isArray
NOOP
} from '@vue/shared'
import {
queueJob,
Expand All @@ -44,7 +44,6 @@ import {
stop,
ReactiveEffectOptions,
isRef,
Ref,
toRaw,
DebuggerEvent
} from '@vue/reactivity'
Expand Down Expand Up @@ -1789,21 +1788,22 @@ function baseCreateRenderer<
}

const setRef = (
ref: string | Function | Ref | [ComponentPublicInstance, string],
oldRef: string | Function | Ref | [ComponentPublicInstance, string] | null,
rawRef: VNodeNormalizedRef,
oldRawRef: VNodeNormalizedRef | null,
parent: ComponentInternalInstance,
value: HostNode | ComponentPublicInstance | null
) => {
if (isArray(ref)) {
// template string refs are compiled into tuples like [ctx, key] to
// ensure refs inside slots are set on the correct owner instance.
const [{ $: owner }, key] = ref
setRef(key, oldRef && (oldRef as any[])[1], owner, value)
const [owner, ref] = rawRef
if (__DEV__ && !owner) {
warn(
`Missing ref owner context. ref cannot be used on hoisted vnodes. ` +
`A vnode with ref must be created inside the render function.`
)
return
}

const refs = parent.refs === EMPTY_OBJ ? (parent.refs = {}) : parent.refs
const renderContext = toRaw(parent.renderContext)
const oldRef = oldRawRef && oldRawRef[1]
const refs = owner.refs === EMPTY_OBJ ? (owner.refs = {}) : owner.refs
const renderContext = toRaw(owner.renderContext)

// unset old ref
if (oldRef !== null && oldRef !== ref) {
Expand All @@ -1827,7 +1827,7 @@ function baseCreateRenderer<
} else if (isRef(ref)) {
ref.value = value
} else if (isFunction(ref)) {
callWithErrorHandling(ref, parent, ErrorCodes.FUNCTION_REF, [value])
callWithErrorHandling(ref, parent, ErrorCodes.FUNCTION_REF, [value, refs])
} else if (__DEV__) {
warn('Invalid template ref type:', value, `(${typeof value})`)
}
Expand Down
16 changes: 13 additions & 3 deletions packages/runtime-core/src/vnode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,17 @@ export type VNodeTypes =
| typeof PortalImpl
| typeof SuspenseImpl

export type VNodeRef =
| string
| Ref
| ((ref: object | null, refs: Record<string, any>) => void)

export type VNodeNormalizedRef = [ComponentInternalInstance, VNodeRef]

export interface VNodeProps {
[key: string]: any
key?: string | number
ref?: string | Ref | ((ref: object | null) => void)
ref?: VNodeRef

// vnode hooks
onVnodeBeforeMount?: (vnode: VNode) => void
Expand Down Expand Up @@ -95,7 +102,7 @@ export interface VNode<HostNode = any, HostElement = any> {
type: VNodeTypes
props: VNodeProps | null
key: string | number | null
ref: string | Ref | ((ref: object | null) => void) | null
ref: VNodeNormalizedRef | null
scopeId: string | null // SFC only
children: VNodeNormalizedChildren<HostNode, HostElement>
component: ComponentInternalInstance | null
Expand Down Expand Up @@ -261,7 +268,10 @@ export function createVNode(
type,
props,
key: props !== null && props.key !== undefined ? props.key : null,
ref: (props !== null && props.ref) || null,
ref:
props !== null && props.ref !== undefined
? [currentRenderingInstance!, props.ref]
: null,
scopeId: currentScopeId,
children: null,
component: null,
Expand Down

0 comments on commit 9ad65b1

Please sign in to comment.