响应工API
reactive
reactive 函数返回对象的响应式副本 proxy 对象,proxy 对象不等于原始对象;proxy 响应式是深层的,会影响所有嵌套 property;
const obj = reactive({ count: 0 })
reactive
会自动解包所有深层的 refs,同时维持 ref 的响应性。
const count = ref(1)
const obj = reactive({ count })
// ref 会被解包
console.log(obj.count === count.value) // true
当将 ref 分配给 reactive
property 时,ref 将被自动解包。
const count = ref(1)
const obj = reactive({})
obj.count = count
console.log(obj.count === count.value) // true
readonly
readonly用于将响应式对象、普通对象、 ref 对象包装成只读代理,与reactive相似,区别在于readonly返回的代理对象及其属性都是只读的;
const original = reactive({ count: 0 })
const copy = readonly(original)
// 变更副本将失败并导致警告
copy.count++ // 警告!
isProxy
检查对象是否是由 reactive
或 readonly
创建的 proxy ;
isReactive
检查对象是否是由 reactive
创建的响应式代理。
const state = reactive({
name: 'John'
})
console.log(isReactive(state)) // -> true
如果该代理是 readonly
创建的,但包裹了由 reactive
创建的另一个代理,它也会返回 true
。
const state = reactive({
name: 'John'
})
// 从普通对象创建的只读 proxy
const plain = readonly({
name: 'Mary'
})
console.log(isReactive(plain)) // -> false
// 从响应式 proxy 创建的只读 proxy
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
标记一个对象,使其永远不会转换为 proxy,返回对象本身。
const foo = markRaw({})
console.log(isReactive(reactive(foo))) // false
// 嵌套在其他响应式对象中时也可以使用
const bar = reactive({ foo })
console.log(isReactive(bar.foo)) // false
shallowReactive(浅层Reactive)
创建一个响应式代理,它跟踪其自身 property 的响应性,但不执行嵌套对象的深层响应式转换 (暴露原始值)。
const state = shallowReactive({
foo: 1,
nested: {
bar: 2
}
})
// 改变 state 本身的性质是响应式的
state.foo++
// ...但是不转换嵌套对象
isReactive(state.nested) // false
state.nested.bar++ // 非响应式
与 reactive
不同,使用 shallowReactive 时,任何使用 ref
的 property 都不会被代理自动解包。
shallowReadonly(浅层只读Reactive)
创建一个 proxy,使其自身的 property 为只读,但不执行嵌套对象的深度只读转换 (暴露原始值)。
const state = shallowReadonly({
foo: 1,
nested: {
bar: 2
}
})
// 改变 state 本身的 property 将失败
state.foo++
// ...但适用于嵌套对象
isReadonly(state.nested) // false
state.nested.bar++ // 适用1
与 readonly
不同,使用 shallowReadonly 时,任何使用 ref
的 property 都不会被代理自动解包。
ref
接受一个内部值并返回一个响应式且可变的 ref 对象,ref 对象仅有一个 .value
property,指向该内部值。
const count = ref(0)
console.log(count.value) // 0
如果将对象分配为 ref 值,则它将被 reactive 函数处理为深层的响应式对象。
如果泛型的类型未知,则建议将 ref
转换为 Ref<T>
:
function useState<State extends string>(initial: State) {
const state = ref(initial) as Ref<State> // state.value -> State extends string
return state
}
unref
如果参数是一个 ref
,则返回内部值,否则返回参数本身
const unwrapped = unref(x) // unwrapped 现在一定是数字类型
toRef
用于为源响应式对象上的某个 property 新创建一个 ref
;然后,ref 可以被传递,它会保持对其源 property 的响应式连接。
const state = reactive({
foo: 1,
bar: 2
})
const fooRef = toRef(state, 'foo')
fooRef.value++
console.log(state.foo) // 2
state.foo++
console.log(fooRef.value) // 3
如果要将 prop 的 ref 传递给复合函数时,toRef
很有用:
setup(props) {
useSomeFeature(toRef(props, 'foo'))
}
即使源 property 不存在,toRef
也会返回一个可用的 ref。这使得它在使用可选 prop 时特别有用,可选 prop 并不会被 toRefs
处理。
toRefs
将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的 ref
。
const state = reactive({
foo: 1,
bar: 2
})
const stateAsRefs = toRefs(state)
/*
stateAsRefs 的类型:
{
foo: Ref<number>,
bar: Ref<number>
}
*/
// ref 和原始 property 已经“链接”起来了
state.foo++
console.log(stateAsRefs.foo.value) // 2
stateAsRefs.foo.value++
console.log(state.foo) // 3
toRefs
会为源对象中包含的 property 生成 ref,如果要为特定的 property 创建 ref,则应当使用 toRef
isRef
检查值是否为一个 ref 对象。
shallowRef(浅层Ref)
创建一个跟踪自身 .value
变化的 ref,但不会使其值也变成响应式的。
const foo = shallowRef({})
// 改变 ref 的值是响应式的
foo.value = {}
// 但是这个值不会被转换。
isReactive(foo.value) // false
shallowRef浅层响应式常用于性能优化,被对象被深层递归;如下:
const state = shallowRef({ count: 1 })
// 不会触发更改
state.value.count = 2
// 会触发更改
state.value = { count: 2 }
triggerRef
默认情况下,value发生改变时 shallowRef 声明的变量才会在视图上进行更新,而 triggerRef 的作用则是手动执行与 shallowRef 关联的任何副作用,强制更新视图。