# ref 的设置和重设
export const setRef = (
rawRef: VNodeNormalizedRef,
oldRawRef: VNodeNormalizedRef | null,
parentComponent: ComponentInternalInstance,
parentSuspense: SuspenseBoundary | null,
vnode: VNode | null
) => {
let value: ComponentPublicInstance | RendererNode | null;
if (!vnode) {
value = null;
} else {
if (vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
value = vnode.component!.proxy;
} else {
value = vnode.el;
}
}
const [owner, ref] = rawRef;
const oldRef = oldRawRef && oldRawRef[1];
const refs = owner.refs === EMPTY_OBJ ? (owner.refs = {}) : owner.refs;
const setupState = owner.setupState;
// unset old ref
if (oldRef != null && oldRef !== ref) {
if (isString(oldRef)) {
refs[oldRef] = null;
if (hasOwn(setupState, oldRef)) {
queuePostRenderEffect(() => {
setupState[oldRef] = null;
}, parentSuspense);
}
} else if (isRef(oldRef)) {
oldRef.value = null;
}
}
if (isString(ref)) {
refs[ref] = value;
if (hasOwn(setupState, ref)) {
queuePostRenderEffect(() => {
setupState[ref] = value;
}, parentSuspense);
}
} else if (isRef(ref)) {
ref.value = value;
} else if (isFunction(ref)) {
callWithErrorHandling(ref, parentComponent, ErrorCodes.FUNCTION_REF, [
value,
refs,
]);
} else if (__DEV__) {
warn("Invalid template ref type:", value, `(${typeof value})`);
}
};
首先获取 value,对于有状态组件,value 是组件的实例的 proxy。而对于无状态组件,则是他的根 dom 节点,vnode.el
。
然后卸载老的 ref,再挂载新的 ref,这里可以看到 ref 可以接受两种值。
- string
- ref
ref
可以通过const myRef = ref()
进行创建,然后直接把myRef
当作参数传递就可以,通过myRef.value
就可以获取节点的值。而对于 string 的 ref,则只能在this.$refs
上进行挂载了。