vue3 中响应式API有哪些?
-
核心响应式 API:创建响应式数据的基础。
-
计算属性与侦听器:派生状态和副作用处理。
-
Ref 相关工具:用于操作和转换
ref。 -
浅层响应式 API:用于性能优化,只处理浅层响应性。
-
原始值操作 API:与响应式系统交互的低级工具。
-
响应式工具函数:用于检查和判断响应式状态。
1. 核心响应式 API
这是创建响应式数据最基础的 API。
reactive()
-
作用:创建一个深度响应式的对象或数组的代理。
-
特点:
-
深度转换:对象的所有嵌套属性都会被递归地转为响应式。
-
仅用于对象类型:不能用于原始值(
string,number,boolean等)。 -
解构丢失响应性:直接对
reactive对象进行 ES6 解构,其属性会失去响应性。需要使用toRefs来解决。
-
-
示例:
import { reactive } from 'vue'; const state = reactive({ count: 0, nested: { value: 'hello' // 这个属性也是响应式的 }, list: [1, 2, 3] }); // 所有操作都是响应式的 state.count++; state.nested.value = 'world'; // 触发更新 state.list.push(4); // 触发更新
readonly()
-
作用:接受一个对象(响应式或普通)或 ref,并返回一个原始对象的只读代理。
-
特点:
-
深度只读:任何尝试设置操作的都会失败并在开发模式下产生警告,包括嵌套属性。
-
与源属性“链接”:如果源对象是响应式的,只读代理会同步变化,只是你不能直接修改它。
-
-
示例:
import { reactive, readonly } from 'vue'; const original = reactive({ count: 0 }); const copy = readonly(original); original.count++; // 成功,copy.count 也会变为 1 copy.count++; // 失败,并会有警告: "Set operation on key 'count' failed: target is readonly."
ref()
-
作用:接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象只有一个
.valueproperty,指向该内部值。 -
特点:
-
可用于任何类型:不像
reactive,ref可以包装任何值,包括原始值和对象。 -
.value访问:在 JS 中读取或修改都需要通过.value,在模板中会自动“解包”,无需.value。 -
对象处理:如果
.value是一个对象,会用reactive()深度转换其值。
-
-
示例:
import { ref } from 'vue'; const count = ref(0); // 原始值 const objectRef = ref({ name: 'Vue' }); // 对象 console.log(count.value); // 0 count.value++; // 修改 console.log(objectRef.value.name); // 'Vue',objectRef.value 是一个 reactive 对象 objectRef.value.name = 'Vue 3'; // 修改<!-- 在模板中自动解包 --> <template> <div>{{ count }}</div> <!-- 无需 .value --> </template>
2. 计算属性与侦听器
computed()
-
作用:创建一个依赖于其他响应式状态的计算属性。
-
特点:
-
缓存:计算结果会被缓存,只有依赖的响应式值发生变化时才会重新计算,性能高效。
-
两种形式:接受一个 getter 函数(只读)或一个带有
get和set函数的对象(可写)。
-
-
示例:
import { ref, computed } from 'vue'; const count = ref(0); // 1. 只读计算属性 const doubleCount = computed(() => count.value * 2); console.log(doubleCount.value); // 0 // 2. 可写计算属性 const writableComputed = computed({ get() { return count.value + 10; }, set(newValue) { count.value = newValue - 10; } }); writableComputed.value = 100; console.log(count.value); // 90
watch()
-
作用:显式地侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。
-
特点:
-
惰性:不会立即执行,只有在源发生变化时执行。
-
精确控制:可以获取变化前的旧值和变化后的新值。
-
多种数据源:可以侦听
ref、reactive对象的属性、getter 函数或以上组成的数组。
-
-
示例:
import { ref, reactive, watch } from 'vue'; const count = ref(0); const state = reactive({ name: 'Alice' }); // 侦听一个 ref watch(count, (newVal, oldVal) => { console.log(`count changed from ${oldVal} to ${newVal}`); }); // 侦听一个 getter 函数(用于 reactive 的某个属性) watch(() => state.name, (newName, oldName) => { console.log(`Name changed from ${oldName} to ${newName}`); }); // 侦听多个源 watch([count, () => state.name], ([newCount, newName], [oldCount, oldName]) => { console.log('Multiple sources changed'); });
watchEffect()
-
作用:立即执行传入的函数,同时自动追踪其依赖,并在其依赖变更时重新运行该函数。
-
特点:
-
自动依赖收集:无需手动指定侦听源,函数体内用到的响应式属性都会被自动收集为依赖。
-
立即执行:会立即运行一次以收集依赖。
-
更简洁:适用于依赖众多且逻辑紧密的场景。
-
-
示例:
import { ref, watchEffect } from 'vue'; const count = ref(0); const stop = watchEffect(() => { // 自动追踪 count.value console.log(`Count is now: ${count.value}`); }); // 立即打印: "Count is now: 0" count.value++; // 重新执行,打印: "Count is now: 1" // 停止侦听器 stop();
3. Ref 相关工具函数
toRef()
-
作用:为源响应式对象上的某个属性创建一个 ref。这个 ref 会与其源属性保持同步。
-
适用场景:当你想要将
props的某个属性传递给一个组合式函数时,确保即使该属性不存在,ref 也会保持响应式。 -
示例:
import { reactive, toRef } from 'vue'; const state = reactive({ foo: 1 }); const fooRef = toRef(state, 'foo'); // 修改 ref 会更新源 fooRef.value++; console.log(state.foo); // 2 // 修改源也会更新 ref state.foo++; console.log(fooRef.value); // 3
toRefs()
-
作用:将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的 ref。
-
适用场景:在从组合式函数返回
reactive对象时,或在解构props时,保持响应性。 -
示例:
import { reactive, toRefs } from 'vue'; function useFeature() { const state = reactive({ x: 0, y: 0 }); // ...逻辑 return toRefs(state); // 返回 { x: Ref<number>, y: Ref<number> } } // 在组件中可以安全解构! const { x, y } = useFeature(); // x 和 y 现在是 refs,模板中可直接使用
isRef()
-
作用:检查一个值是否为一个 ref 对象。
-
示例:
import { ref, isRef } from 'vue'; const count = ref(0); console.log(isRef(count)); // true console.log(isRef(0)); // false
unref()
-
作用:这是一个语法糖:
val = isRef(val) ? val.value : val。 -
适用场景:在可能接收到 ref 或普通值的函数中非常有用。
-
示例:
function useValue(maybeRef) { const value = unref(maybeRef); // 如果是 ref,取 .value,否则直接返回值 // ...使用 value }
4. 浅层响应式 API (性能优化)
这些 API 只创建浅层响应式对象,忽略嵌套属性的响应式转换,在某些场景下可以提升性能。
shallowRef()
-
作用:创建一个 ref,只跟踪其
.value本身的变化,不关心.value内部的属性。 -
与
ref区别:ref会深度转换对象,shallowRef不会。 -
适用场景:存储大型数据结构(如复杂的嵌套对象)或不需要深度监听变化的外部第三方类实例。
-
示例:
import { shallowRef, triggerRef } from 'vue'; const bigObject = shallowRef({ deep: { nested: { value: 1 } } }); // 这不会触发更新! bigObject.value.deep.nested.value = 2; // 这会触发更新,因为替换了整个 `.value` bigObject.value = { new: 'object' }; // 强制触发更新(慎用) triggerRef(bigObject);
shallowReactive()
-
作用:创建一个响应式代理,只跟踪其自身属性的响应性(第一层属性),忽略所有深层属性的响应性。
-
与
reactive区别:reactive是深度的,shallowReactive是浅层的。 -
示例:
import { shallowReactive } from 'vue'; const state = shallowReactive({ rootLevel: 'reactive', nested: { deepData: 'not reactive' } }); state.rootLevel = 'new'; // 响应式,触发更新 state.nested.deepData = 'new'; // 非响应式,不触发更新!
shallowReadonly()
-
作用:类似于
readonly(),但只将根级别属性设置为只读,深层属性仍然可以被修改(尽管不是响应式的)。 -
示例:
import { shallowReadonly } from 'vue'; const state = shallowReadonly({ root: 'readonly', nested: { value: 'writable' } }); state.root = 'new'; // 失败,警告 state.nested.value = 'new'; // 成功!但不会触发响应式更新
5. 原始值操作 API (高级)
toRaw()
-
作用:返回由
reactive()、readonly()、shallowReactive()或shallowReadonly()创建的代理对应的原始对象。 -
适用场景:用于临时读取数据而不会引起代理访问/跟踪开销,或是用于修改数据而不触发变更(谨慎使用!)。
-
示例:
import { reactive, toRaw } from 'vue'; const foo = {}; const reactiveFoo = reactive(foo); console.log(toRaw(reactiveFoo) === foo); // true
markRaw()
-
作用:标记一个对象,使其永远不会被转换为代理。返回对象本身。
-
适用场景:当你有一个复杂的第三方类实例,或者一个不可变的数据结构,并且确信它们不需要响应性时,用于性能优化。
-
示例:
import { reactive, markRaw } from 'vue'; const complexObject = markRaw({ // ...大型复杂数据,或第三方实例 }); const state = reactive({ // 即使嵌套在 reactive 中,complexObject 也不会被转为代理 data: complexObject });
6. 响应式工具函数
isReactive()
-
作用:检查一个对象是否是由
reactive()或shallowReactive()创建的代理。isReactive(reactive({})); // true
isReadonly()
-
作用:检查一个对象是否是由
readonly()或shallowReadonly()创建的代理。isReadonly(readonly(reactive({}))); // true
isProxy()
-
作用:检查一个对象是否是由
reactive(),readonly(),shallowReactive()或shallowReadonly()创建的代理。isProxy(reactive({})); // true isProxy(readonly({})); // true
总结与选择指南
| 你的需求 | 推荐使用的 API |
|---|---|
| 创建一个基本类型的响应式变量 | ref |
| 创建一个复杂对象/数组的响应式变量 | reactive |
| 基于其他状态创建一个派生值 | computed |
| 侦听响应式状态的变化并执行副作用 | watch / watchEffect |
解构 reactive 对象或 props 并保持响应性 |
toRefs |
将 props 的某个属性安全传递给组合式函数 |
toRef |
| 需要一个大型对象的响应式,但性能是关键 | shallowRef / shallowReactive |
| 需要创建一个不允许修改的响应式对象 | readonly / shallowReadonly |
| 需要跳过代理,直接操作或读取原始对象 | toRaw |
| 确保一个对象永远不会被转为响应式代理 | markRaw |
更多推荐




所有评论(0)