Refs 是 Vue 和 React 中用于直接访问 DOM 或组件实例的“逃生舱”,仅在聚焦输入框、调用子组件命令式方法、v-for 批量操作节点等特定场景下推荐使用,须避免在模板读取、替代响应式状态、v-if 未满足时访问,并严守时机与作用域底线。

Refs 是 Vue 和 React 中用于直接访问 DOM 元素或组件实例的“逃生舱”,不是首选通信方式,而是在声明式逻辑无法覆盖的特定场景下才启用。用得对,能快速解决问题;用错了,容易引发 undefined、时机错误、响应式失效甚至性能隐患。
该用 Refs 的明确场景
以下情况属于合理且推荐使用 refs 的典型用例:
-
聚焦输入框或滚动定位:比如表单提交后自动聚焦第一个错误字段,或页面加载后滚动到某个区域 —— 这类纯 DOM 操作无需状态驱动,直接调用
.focus()或.scrollIntoView()最自然。 -
调用子组件的命令式方法:当子组件封装了编辑器(如 Tiptap)、画布(如 Fabric.js)、视频播放器等复杂外部库时,父组件需要触发其专属 API(如
editor.value.setContent()或canvas.clear()),而这些方法不适合也不应通过 props + 事件反复暴露。 - v-for 列表中批量操作节点:例如需同时获取所有表格行的 DOM 高度做对齐,或为每个 canvas 实例单独初始化 —— 此时 ref 会自动收集为数组,比手动 querySelector 更可靠。
必须避开 Refs 的关键情形
这些做法看似方便,实则违背响应式设计原则,易埋坑:
React 与 Next.js 性能优化指南,源自 Vercel 工程团队。适用于编写、审查或重构 React/Next.js 代码时使用。
-
在模板中读取 $refs 或 ref.value:比如
{{ $refs.input?.value }}或v-show="!!$refs.child"—— $refs 非响应式,模板不会随其变化重新计算,且渲染初期为空,极易报错或显示异常。 -
用 ref 替代响应式数据管理状态:例如把用户信息存进
const user = ref({ name: '' })后又频繁修改user.value.name却不依赖它触发视图更新 —— 这等于绕过 Vue 的响应系统,失去自动同步能力。 - 在 v-if 条件未满足时提前访问 ref:v-if 会让元素/组件完全不渲染,此时 $refs 对应字段为 undefined。若逻辑未加判空或未等条件成立后再调用,就会触发 “Cannot read property ‘xxx’ of undefined”。
替代方案优先级建议
遇到想用 ref 的需求,先问自己:是否真需要命令式访问?多数时候有更健壮的替代路径:
- 父子通信优先用 props + emits:子组件内部状态变更 → 通过事件通知父组件;父组件控制行为 → 通过 props 传配置或指令。
- 跨层级访问考虑 provide/inject:尤其适用于主题、国际化、权限等上下文类数据,比层层透传 ref 更清晰。
-
DOM 状态映射用 v-model 或 watch:比如输入框值,用
v-model绑定响应式变量,比反复读$refs.input.value更安全、可测试。
安全使用的硬性前提
只要用 refs,就必须守住两条底线:
-
时机守恒:确保只在组件已挂载(
onMounted/mounted)之后访问;异步条件(如 v-if 切换、动态加载)下,务必配合v-show或nextTick+ 判空逻辑。 - 作用域收敛:ref 只用于当前组件可控范围内的 DOM 或子组件,绝不跨组件边界直接修改他人内部状态 —— 否则会破坏封装,导致维护成本飙升。

















