Skip to content

Commit

Permalink
feat(runtime-vapor, compiler-vapor): impl setRef update
Browse files Browse the repository at this point in the history
close #190
  • Loading branch information
Doctor-wu committed Apr 26, 2024
1 parent 464b498 commit dcaad1d
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`compiler: template ref transform > dynamic ref 1`] = `
"import { setRef as _setRef, template as _template } from 'vue/vapor';
"import { renderEffect as _renderEffect, setRef as _setRef, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
_setRef(n0, _ctx.foo)
let r0
_renderEffect(() => r0 = _setRef(n0, _ctx.foo, r0))
return n0
}"
`;
Expand All @@ -18,7 +19,7 @@ const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = _createFor(() => ([1,2,3]), (_block) => {
const n2 = t0()
_setRef(n2, "foo", true)
_setRef(n2, "foo", undefined, true)
return [n2, () => {}]
})
return n0
Expand All @@ -32,7 +33,7 @@ const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = _createIf(() => (true), () => {
const n2 = t0()
_setRef(n2, "foo")
_setRef(n2, "foo", undefined)
return n2
})
return n0
Expand All @@ -45,7 +46,7 @@ const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
_setRef(n0, "foo")
_setRef(n0, "foo", undefined)
return n0
}"
`;
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe('compiler: template ref transform', () => {
})

expect(code).matchSnapshot()
expect(code).contains('_setRef(n0, "foo")')
expect(code).contains('_setRef(n0, "foo", undefined)')
})

test('dynamic ref', () => {
Expand All @@ -70,7 +70,7 @@ describe('compiler: template ref transform', () => {
},
})
expect(code).matchSnapshot()
expect(code).contains('_setRef(n0, _ctx.foo)')
expect(code).contains('_setRef(n0, _ctx.foo, r0)')
})

test('ref + v-if', () => {
Expand Down Expand Up @@ -98,7 +98,7 @@ describe('compiler: template ref transform', () => {
})

expect(code).matchSnapshot()
expect(code).contains('_setRef(n2, "foo")')
expect(code).contains('_setRef(n2, "foo", undefined)')
})

test('ref + v-for', () => {
Expand All @@ -122,6 +122,6 @@ describe('compiler: template ref transform', () => {
refFor: true,
})
expect(code).matchSnapshot()
expect(code).contains('_setRef(n2, "foo", true)')
expect(code).contains('_setRef(n2, "foo", undefined, true)')
})
})
8 changes: 8 additions & 0 deletions packages/compiler-vapor/src/generators/ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,21 @@ export function genSetRef(
context: CodegenContext,
): CodeFragment[] {
const { vaporHelper } = context
const dynamicExp = oper.refCount !== -1
return [
NEWLINE,
dynamicExp && `let r${oper.refCount}`,
dynamicExp && NEWLINE,
...(!!dynamicExp
? [`${vaporHelper('renderEffect')}(() => `, `r${oper.refCount} = `]
: []),
...genCall(
vaporHelper('setRef'),
[`n${oper.element}`],
genExpression(oper.value, context),
[dynamicExp ? `r${oper.refCount}` : 'undefined'],
oper.refFor && 'true',
),
!!dynamicExp && ')',
]
}
1 change: 1 addition & 0 deletions packages/compiler-vapor/src/ir.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ export interface SetRefIRNode extends BaseIRNode {
element: number
value: SimpleExpressionNode
refFor: boolean
refCount: number
}

export interface SetModelValueIRNode extends BaseIRNode {
Expand Down
3 changes: 3 additions & 0 deletions packages/compiler-vapor/src/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ export interface TransformContext<T extends AllNode = AllNode> {

component: Set<string>

refCount: number

enterBlock(ir: TransformContext['block'], isVFor?: boolean): () => void
reference(): number
increaseId(): number
Expand Down Expand Up @@ -152,6 +154,7 @@ function createRootContext(
inVFor: 0,
comment: [],
component: root.component,
refCount: 0,

increaseId: () => globalId++,
reference() {
Expand Down
7 changes: 5 additions & 2 deletions packages/compiler-vapor/src/transforms/transformRef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
import type { NodeTransform } from '../transform'
import { IRNodeTypes } from '../ir'
import { normalizeBindShorthand } from './vBind'
import { findProp } from '../utils'
import { findProp, isConstantExpression } from '../utils'
import { EMPTY_EXPRESSION } from './utils'

export const transformRef: NodeTransform = (node, context) => {
Expand All @@ -24,11 +24,14 @@ export const transformRef: NodeTransform = (node, context) => {
: EMPTY_EXPRESSION
}

return () =>
return () => {
const dynamicExp = !isConstantExpression(value)
context.registerOperation({
type: IRNodeTypes.SET_REF,
element: context.reference(),
value,
refFor: !!context.inVFor,
refCount: dynamicExp ? context.refCount++ : -1,
})
}
}
73 changes: 72 additions & 1 deletion packages/runtime-vapor/__tests__/dom/templateRef.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { ref, setRef, template } from '../../src'
import type { NodeRef } from 'packages/runtime-vapor/src/dom/templateRef'
import {
createIf,
nextTick,
ref,
renderEffect,
setRef,
template,
} from '../../src'
import { makeRender } from '../_utils'

const define = makeRender()
Expand All @@ -23,4 +31,67 @@ describe('api: template ref', () => {
const { host } = render()
expect(el.value).toBe(host.children[0])
})

it('string ref update', async () => {
const t0 = template('<div></div>')
const fooEl = ref(null)
const barEl = ref(null)
const refKey = ref('foo')

const { render } = define({
setup() {
return {
foo: fooEl,
bar: barEl,
}
},
render() {
const n0 = t0()
let r0: NodeRef | undefined
renderEffect(() => {
r0 = setRef(n0 as Element, refKey.value, r0)
})
return n0
},
})
const { host } = render()
expect(fooEl.value).toBe(host.children[0])
expect(barEl.value).toBe(null)

refKey.value = 'bar'
await nextTick()
expect(barEl.value).toBe(host.children[0])
expect(fooEl.value).toBe(null)
})

it('string ref unmount', async () => {
const t0 = template('<div></div>')
const el = ref(null)
const toggle = ref(true)

const { render } = define({
setup() {
return {
refKey: el,
}
},
render() {
const n0 = createIf(
() => toggle.value,
() => {
const n1 = t0()
setRef(n1 as Element, 'refKey')
return n1
},
)
return n0
},
})
const { host } = render()
expect(el.value).toBe(host.children[0])

toggle.value = false
await nextTick()
expect(el.value).toBe(null)
})
})
20 changes: 19 additions & 1 deletion packages/runtime-vapor/src/dom/templateRef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ export type RefEl = Element | ComponentInternalInstance
/**
* Function for handling a template ref
*/
export function setRef(el: RefEl, ref: NodeRef, refFor = false) {
export function setRef(
el: RefEl,
ref: NodeRef,
oldRef?: NodeRef,
refFor = false,
) {
if (!currentInstance) return
const { setupState, isUnmounted } = currentInstance

Expand All @@ -42,6 +47,18 @@ export function setRef(el: RefEl, ref: NodeRef, refFor = false) {
? (currentInstance.refs = {})
: currentInstance.refs

// dynamic ref changed. unset old ref
if (oldRef != null && oldRef !== ref) {
if (isString(oldRef)) {
refs[oldRef] = null
if (hasOwn(setupState, oldRef)) {
setupState[oldRef] = null
}
} else if (isRef(oldRef)) {
oldRef.value = null
}
}

if (isFunction(ref)) {
const invokeRefSetter = (value?: Element | Record<string, any>) => {
callWithErrorHandling(
Expand Down Expand Up @@ -117,4 +134,5 @@ export function setRef(el: RefEl, ref: NodeRef, refFor = false) {
warn('Invalid template ref type:', ref, `(${typeof ref})`)
}
}
return ref
}

0 comments on commit dcaad1d

Please sign in to comment.