Vue3响应式API是Vue3中新增的一种API,它可以帮助开发者更好地管理数据流,并且可以更快地实现数据的双向绑定。
Vue3响应式API的核心是响应式对象(Reactive Object),它是一个特殊的JavaScript对象,其中包含了一些特殊的属性。这些特殊的属性会被Vue3监听,当这些属性发生变化时,Vue3会自动重新渲染页面。
使用Vue3响应式API最重要的就是要创建一个Reactive Object。创建Reactive Object有两种方法:一种是使用Ref函数来创建Ref对象,另一种是使用reactive函数来创建Reactive Object。
// 使用Ref函数创建Ref对象 const count = ref(0); // 使用reactive函数创建Reactive Object const state = reactive({ count: 0 });
当我们创建好Reactive Object之后,就可以在我们的代码中使用它了。我们可以通过getter/setter方法来读写Reactive Object中的数据。例如我们想要读写count字段时:
// 读count字段 const currentCount = state.count; // 写count字段 state.count = 10;
此外,Vue3还新加入了watch函数来监听Reactive Object中字段的变化。watch函数会在字段变化时执行回调函数。例如我们想要监听state.count字段时:
watch(() => state.count, (newValue, oldValue) => { // 在state.count字段变化时执行回调函数 console.log('state.count changed from', oldValue, 'to', newValue); });
总之,Vue3新加入的响应式API能够带来很大便利性、易用性、高性能等优势。它不但能够带来很好地代码体验,而且也能够大大加快开发速度、降低代码复杂度、保证代码正确性、保证代码易读性、保证代码易测试性、保证代码易扩展性。因此Vue3新加入的这个API将会大大影响前端开发者在工作中的体验感。
本节例子中代码使用的单文件组件语法
reactive
返回对象的响应式副本
const obj = reactive({ count: 0 })
响应式转换是“深层”的——它影响所有嵌套 property。在基于 ES2015 Proxy 的实现中,返回的代理是不等于原始对象。建议只使用响应式代理,避免依赖原始对象。
类型声明:
function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
readonly
获取一个对象 (响应式或纯对象) 或 ref 并返回原始代理的只读代理。只读代理是深层的:访问的任何嵌套 property 也是只读的。
const original = reactive({ count: 0 })
const copy = readonly(original)
watchEffect(() => {
// 适用于响应性追踪
console.log(copy.count)
})
// 变更original 会触发侦听器依赖副本
original.count++
// 变更副本将失败并导致警告
copy.count++ // 警告!
isProxy
检查对象是 reactive
还是 readonly
创建的代理
isReactive
检查对象是否是 reactive
创建的响应式 proxy。
import { reactive, isReactive } from "vue"
export default {
setup() {
const state = reactive({
name: "John"
})
console.log(isReactive(state)) // -> true
}
}
如果 proxy 是 readonly
创建的,但还包装了由 reactive
创建的另一个 proxy,它也会返回 true
。
import { reactive, isReactive, readonly } from "vue"
export default {
setup() {
const state = reactive({
name: "John"
})
// 从普通对象创建的只读代理
const plain = readonly({
name: "Mary"
})
console.log(isReactive(plain)) // -> false
// 从响应式代理创建的只读代理
const stateCopy = readonly(state)
console.log(isReactive(stateCopy)) // -> true
}
}
isReadonly
检查对象是否是由readonly
创建的只读代理。
toRaw
返回 reactive
或 readonly
代理的原始对象。这是一个转义口,可用于临时读取而不会引起代理访问/跟踪开销,也可用于写入而不会触发更改。不建议保留对原始对象的持久引用。请谨慎使用。
const foo = {}
const reactiveFoo = reactive(foo)
console.log(toRaw(reactiveFoo) === foo) // true
markRaw
标记一个对象,使其永远不会转换为代理。返回对象本身。
const foo = markRaw({})
console.log(isReactive(reactive(foo))) // false
// 嵌套在其他响应式对象中时也可以使用
const bar = reactive({ foo })
console.log(isReactive(bar.foo)) // false
WARNING
下方的 markRaw
和 shallowXXX API 使你可以有选择地选择退出默认的深度响应式/只读转换,并将原始的,非代理的对象嵌入状态图中。它们可以在各种情况下使用:
它们被认为是高阶的,因为原始选择退出仅在根级别,因此,如果将嵌套的、未标记的原始对象设置为响应式对象,然后再次访问它,则可以得到代理版本。这可能会导致本源危害——即执行依赖于对象本身但同时使用同一对象的原始版本和代理版本的操作:
const foo = markRaw({
nested: {}
})
const bar = reactive({
// 虽然 `foo` 被标记为原始,foo.nested 不是。
nested: foo.nested
})
console.log(foo.nested === bar.nested) // false
本源危害通常很少见。然而,为了在安全地避免本源危害的同时正确地使用这些 API,需要对响应性系统的工作原理有一个坚实的理解。
shallowReactive
创建一个响应式代理,该代理跟踪其自身 property 的响应性,但不执行嵌套对象的深度响应式转换 (暴露原始值)。
const state = shallowReactive({
foo: 1,
nested: {
bar: 2
}
})
// 改变状态本身的性质是响应式的
state.foo++
// ...但是不转换嵌套对象
isReactive(state.nested) // false
state.nested.bar++ // 非响应式
shallowReadonly
创建一个代理,使其自身的 property 为只读,但不执行嵌套对象的深度只读转换 (暴露原始值)。
const state = shallowReadonly({
foo: 1,
nested: {
bar: 2
}
})
// 改变状态本身的property将失败
state.foo++
// ...但适用于嵌套对象
isReadonly(state.nested) // false
state.nested.bar++ // 适用
#计算属性模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如...
#v-ifv-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。h1 v-if="awesome"Vue is aw...
#基础用法你可以用 v-model 指令在表单 input、textarea 及 select 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方...
该页面假设你已经阅读过了组件基础。如果你还对组件不太了解,推荐你先阅读它。一个非 prop 的 attribute 是指传向一个组件,但...
该页面假设你已经阅读过了组件基础。如果你还对组件不太了解,推荐你先阅读它。#在动态组件上使用 keep-alive我们之前曾经在一个...