Vue 3 触发更新:key 强制重渲、triggerRef、nextTick 与解构丢失响应式

Vue 3 响应式自动更新

Vue 3 中 refreactive 的数据修改会自动触发组件重新渲染,无需手动操作:

const count = ref(0);
count.value++;  // 自动触发更新

const state = reactive({ name: 'hello' });
state.name = 'world';  // 自动触发更新

强制重建组件:修改 :key

当需要完全销毁并重新创建一个组件(而不只是更新数据)时,修改 :key 是最推荐的方式:

<template>
    <MyComponent :key="refreshKey" :data="data" />
    <button @click="refreshKey++">强制刷新</button>
</template>

<script setup>
import { ref } from 'vue';
const refreshKey = ref(0);
</script>

:key 变化会让 Vue 销毁旧组件实例并创建新的,适合需要重置内部状态的场景。

shallowRef 深层修改:triggerRef

shallowRef 只追踪引用本身的变化,不追踪对象内部属性:

import { shallowRef, triggerRef } from 'vue';

const data = shallowRef({ list: [] });

data.value.list.push(1);  // 不触发更新!
triggerRef(data);          // 手动通知 Vue 重新渲染

非必要不用 shallowRef,直接用 ref 更简单。

nextTick:等待 DOM 更新完成

数据变更后,DOM 不会立即同步更新(Vue 批量异步更新),需要 nextTick 等待:

import { ref, nextTick } from 'vue';

const visible = ref(false);
visible.value = true;

await nextTick();
// 此时 DOM 已更新,可以安全操作 DOM 元素
const el = document.querySelector('.new-element');

常见陷阱:解构 reactive 丢失响应式

const state = reactive({ count: 1, name: 'hello' });

// 错误:解构后 count 是普通变量,不是响应式
const { count } = state;
count;  // 修改不会触发更新

// 正确:用 toRefs 保留响应式
import { toRefs } from 'vue';
const { count, name } = toRefs(state);
count.value++;  // 正确触发更新

ref 不存在这个问题,因为 ref 返回的是包装对象,count.value 始终访问同一个响应式引用。

Vue 2 迁移注意

Vue 2 中直接对数组索引赋值、添加新属性不响应,需要 $set

// Vue 2
this.$set(this.arr, 0, newValue);
this.$set(this.obj, 'newKey', 1);

Vue 3 用 Proxy 实现响应式,这两种写法都能正确追踪,不需要 $set

$forceUpdate(不推荐)

import { getCurrentInstance } from 'vue';
const instance = getCurrentInstance();
instance.proxy.$forceUpdate();

$forceUpdate 只强制当前组件实例重渲染,不更新子组件,且不解决数据不响应的根本问题。遇到更新问题应优先排查响应式数据的使用方式,而不是调用 $forceUpdate