vue3学习笔记——第二节
1. 组合式API
1. provide与inject
- 官方文档:provide 和 inject 启用依赖注入。这两者只能在使用当前活动实例的 setup() 期间被调用。
- 作用:实现祖组件和后代组件间通信(两级以上)
- 使用方式:祖组件使用 provide 提供数据;后代组件使用 inject 接受数据
// 祖组件使用provide提供数据
let person = 'wmh'
provide('person', person)
// 后代组件使用inject接收数据
let person = inject('person')
2. 生命周期钩子
可以通过直接导入 onX 函数来注册生命周期钩子:(X表示原有选项式 API)
import { onMounted, onUpdated, onUnmounted } from 'vue'
const MyComponent = {
setup() {
onMounted(() => {
console.log('mounted!')
})
onUpdated(() => {
console.log('updated!')
})
onUnmounted(() => {
console.log('unmounted!')
})
}
}
2. 响应式API
1. toRef和toRefs函数
1. toRef
- 官方文档:可以用来为源响应式对象上的某个 property 新创建一个 ref。然后,ref 可以被传递,它会保持对其源 property 的响应式连接。
import { toRef } from 'vue'
- 简单说:创建一个ref对象,其value值指向另一个对象的某个属性,这两个值互相联系
let state = reactive({
foo: 1,
bar: 2
})
let fooRef = toRef(state, 'foo')
fooRef.value++
console.log(state.foo) // 输出:2
state.foo++
console.log(fooRef.value) // 输出:3
应用场景:需要将响应式对象中的某个值单独提供给外部,或是提供给某个方法时
useSomeFeature(toRef(state, 'foo'))
需要注意的是,即使源property(例如上述的state.foo)不存在,toRef也会返回一个可用的ref
2. toRefs
- 官方文档:将响应式对象转换为普通对象(ref对象),其中结果对象的每个 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
2. readonly和shallowReadonly函数
1. readonly
- 官方文档:接受一个对象 (响应式或纯对象) 或 ref 并返回原始对象的只读代理。只读代理是深层的:任何被访问的嵌套 property 也是只读的。
import { readonly, shallowReadonly } from 'vue'
- 理解:包裹一个响应式数据返回该数据的只读代理
const original = reactive({ count: 0 })
const copy = readonly(original)
// 变更 original 正常执行
original.count++
// 变更副本将失败并导致警告
copy.count++ // 警告!
只读代理是深层的:任何被访问的嵌套 property 也是只读的。
2. shallowReadonly
- 官方文档:创建一个 proxy,使其自身的 property 为只读,但不执行嵌套对象的深度只读转换 (暴露原始值)。
const state = shallowReadonly({
foo: 1,
nested: {
bar: 2
}
})
// 改变 state 本身的 property 将失败
state.foo++
// ...但适用于嵌套对象
isReadonly(state.nested) // false
state.nested.bar++ // 正常执行
- 理解:浅层的readonly,只会影响源数据自身的property,不影响嵌套对象
3. shallowRef和shallowReactive函数
1. shallowRef
- 官方文档:创建一个跟踪自身 .value 变化的 ref,但不会使其值也变成响应式的。
- 理解:只处理基本类型的响应式,不进行对象的响应式处理
2. shallowReactive
- 官方文档:创建一个响应式代理,它跟踪其自身 property 的响应性,但不执行嵌套对象的深层响应式转换 (暴露原始值)。
- 理解:只处理对象最外层的响应式(浅响应式)
const state = shallowReactive({
foo: 1,
nested: {
bar: 2
}
})
// 改变 state 本身的性质是响应式的
state.foo++
// ...但是不转换嵌套对象
isReactive(state.nested) // false
state.nested.bar++ // 非响应式
4. toRaw和markRaw函数
1. toRaw(请谨慎使用)
- 官方文档:返回 reactive 或 readonly 代理的原始对象。
import { toRaw, markRaw } from 'vue'
- 理解:将一个由 reactive 或 readonly 生成的响应式对象转为普通对象,对这个普通对象的所有操作,不会引起页面更新(数据会发生改变)
const foo = {}
const reactiveFoo = reactive(foo)
console.log(toRaw(reactiveFoo) === foo) // true
2. markRaw
- 官方文档:标记一个对象,使其永远不会转换为 proxy,返回对象本身。
const foo = markRaw({})
console.log(isReactive(reactive(foo))) // false
// 嵌套在其他响应式对象中时也可以使用
const bar = reactive({ foo })
console.log(isReactive(bar.foo)) // false
markRaw 和上述的 shallowXXX API 使你可以有选择地退出默认的深度响应式/只读转换模式,并将原始的,未被代理的对象嵌入状态图中。
3. customRef
- 官方文档:创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。它需要一个工厂函数,该函数接收 track 和 trigger 函数作为参数,并且应该返回一个带有 get 和 set 的对象。
- 典例:使用自定义 ref 通过 v-model 实现 debounce 的示例:
<input v-model="text" />
function useDebouncedRef(value, delay = 200) {
let timeout //定义延迟
return customRef((track, trigger) => {
return {
get() {
track()
return value
},
set(newValue) {
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
trigger()
}, delay)
}
}
})
}
export default {
setup() {
return {
text: useDebouncedRef('hello')
}
}
}
5. 响应式数据的判断
- isRef:判断一个值是否为一个ref对象
- isReactive:判断一个对象是否是由Reactive创建的响应式代理
- isReadonly:判断一个对象是否是由readonly创建的响应式代理
- isProxy:判断一个对象是否是由Reactive或readonly创建的响应式代理
let name = ref('wmh')
isRef(name) // true
isReactive(name) // false