vue 3 中 reactive 触发视图更新的最小粒度是对象的单个属性级别,依赖“谁被读、谁被追踪”机制:仅模板或 effect 中实际访问的属性(如 user.name)建立响应依赖,修改未读取属性不触发更新;解构、直接替换 reactive 对象或数组索引赋值会破坏该粒度。

Vue 3 中 reactive 触发视图更新的最小粒度是对象的单个属性(property)级别,不是整个对象,也不是整个组件,更不是 DOM 节点。
属性粒度依赖:谁被读,谁才被追踪
Vue 3 的响应式系统在模板或 effect 中首次访问某个属性(如 user.name 或 list[0].id)时,会通过 Proxy.get 拦截并调用 track(),将当前副作用(比如组件渲染函数)记录为该属性的依赖。这意味着:
- 只读了
state.profile.avatar,那只有这个属性建立依赖;改state.profile.name不会触发更新 - 模板中用了
v-for="item in list",实际会逐个访问list.length和每个list[i]的属性,所以增删数组项、修改某一项字段都可能精准触发对应片段重渲染 - 即使对象深度嵌套,只要没在模板里显式读取某一层(比如没写
user.settings.theme),那一层就不会建立依赖,也不会因它变化而更新
不等于“DOM 节点级”更新,但能支撑精细化渲染
属性粒度是依赖收集的最小单位,不是最终 DOM 操作的最小单位。Vue 仍以组件为更新边界,但借助编译器优化(如静态提升、补丁标志),可让 diff 精准定位到受影响的子树。例如:
- 一个
<div>{{ user.name }}</div>和<p>{{ user.age }}</p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill4595" title="Auth0 React"><img src="https://img.php.cn/upload/skill/000/000/081/179013608567034.jpg" alt="Auth0 React" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/xiazai/skill4595" title="Auth0 React" class="overflowclass">Auth0 React</a> <p class="overflowclass">已弃用 — 请改用 `auth0` 技能(运行 `npx clawhub install auth0`)。适用于为 React 单页应用(SPA)添加 Auth0 登录、登出、受保护路由或用户会话功能。该技能集成 `@auth0/auth0-react` — 即使用户仅表述为“为我的 React 应用添加登录功能”或“保护我的 React 路由”,而未明确提及 Auth0,也应使用此技能。</p> </div> <a rel="nofollow" href="/xiazai/skill4595" title="Auth0 React" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div>分属不同节点,user.name变化只会更新<div> 内容,不影响 <code><p></p> - 用
v-if包裹的区块,其依赖只存在于条件成立时;条件切换后,整块内容卸载,不参与后续依赖追踪 -
直接替换整个 reactive 对象:如
state = reactive({ ... })—— 新对象无旧依赖,旧引用丢失 -
数组索引直接赋值:如
arr[0] = newItem—— Proxy 能拦截,但某些运行时场景下可能绕过依赖通知(推荐用splice或push) -
解构后使用:如
const { name } = state—— 解构得到的是普通值,脱离响应式链路
哪些操作会破坏属性粒度?
以下写法会让 Vue 无法按属性粒度响应,退化为“对象级”甚至“组件级”更新:
ref 与 reactive 的粒度一致,只是入口不同
ref(x) 本质是 reactive({ value: x }),所以它的最小响应粒度也是 .value 这个属性。你在模板中写 {{ count }},Vue 自动解包成 count.value,依赖收集就落在 value 属性上。和 reactive 一样,改其他未被读取的字段,不会触发更新。









