Allow mergeProps to merge `ref` property
What problem does this feature solve?
Consider you are writing a hook that decorates element with property
// this will make dom element draggable with mouse with the force of css transform
const useDraggable = () => {
const element = ref()
onMounted(() => {
// do something with element to get dimension of element... etc
})
return {
domProperties: 'xxx',
onSomeHandler: () => { /* ooo */ },
ref: element
}
}
The returned object contains handler and ref that it need to work with.
And you use it in this way
<template>
<MyOtherComponent ref="comp" v-bind="props"></MyOtherComponent>
</template>
<script>
const comp = ref()
const props = useDraggable()
onMounted(() => {
// do something with the `comp`
})
</script>
However, the comp
ref don't work unless you specifically workaround it.
Because mergeProps only merge class
style
onXXX
.
The ref
is simply got overwritten, so you get undefined
in comp
What does the proposed API look like?
No API change, only implementation change in
to create a proxied ComputedRef
that forward dom value to ref
of every incoming props source
probably something like
export function mergeProps(...args: (Data & VNodeProps)[]) {
const ret: Data = {}
// ===== PATCH START =====
const refs = []
// ===== PATCH END=====
for (let i = 0; i < args.length; i++) {
const toMerge = args[i]
for (const key in toMerge) {
if (key === 'class') {
if (ret.class !== toMerge.class) {
ret.class = normalizeClass([ret.class, toMerge.class])
}
} else if (key === 'style') {
ret.style = normalizeStyle([ret.style, toMerge.style])
// ===== PATCH START =====
} else if (key === 'ref') {
ret[key] = toMerge[key]
refs.push(toMerge.ref)
// ===== PATCH END=====
} else if (isOn(key)) {
const existing = ret[key]
const incoming = toMerge[key]
if (
incoming &&
existing !== incoming &&
!(isArray(existing) && existing.includes(incoming))
) {
ret[key] = existing
? [].concat(existing as any, incoming as any)
: incoming
}
} else if (key !== '') {
ret[key] = toMerge[key]
}
}
}
// ===== PATCH START =====
if (refs.length > 1) {
const refProxy = computed({
set (v) {
for (const r of refs) {
r.value = v
}
},
get () {
return refs[0].value
}
})
ret.ref = refProxy
}
// ===== PATCH END=====
return ret
}
There may be more case because ref can be string or setter or undefined, but the basic idea is like above