shallowRef 与 shallowReactive
对于深层次的对象,shallowRef 与 shallowReactive 只将最外层的对象转换为响应式数据,用于对大型数据结构的性能优化或是与外部的状态管理系统集成
shallowRef
:只对 .value
的访问是响应式的
shallowReactive
:内部的 ref 数据不会被自动解包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| const state = shallowRef({ count: 1 })
state.value.count = 2
state.value = { count: 2 }
const state = shallowReactive({ foo: 1, nested: { bar: 2 } })
state.foo++
isReactive(state.nested)
state.nested.bar++
|
readonly 与 shallowReadonly
readonly
:创建一个响应式数据的只读响应式副本,随原数据变化触发响应式更新
shallowReadonly
:只将最外层对象的属性变为了只读
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| const original = reactive({ count: 0 })
const copy = readonly(original)
watchEffect(() => { console.log(copy.count) })
original.count++
copy.count++
const state = shallowReadonly({ foo: 1, nested: { bar: 2 } })
state.foo++
isReadonly(state.nested)
state.nested.bar++
|
toRaw 与 markRaw
toRaw
:返回响应式数据的原始数据
markRaw
:将一个对象标记为不可被转为代理,返回该对象本身
1 2 3 4 5 6 7 8 9 10 11 12 13
| const foo = {} const reactiveFoo = reactive(foo)
console.log(toRaw(reactiveFoo) === foo)
const foo = markRaw({}) console.log(isReactive(reactive(foo)))
const bar = reactive({ foo }) console.log(isReactive(bar.foo))
|
customRef
创建一个自定义的 ref,显式声明对其依赖追踪和更新触发的控制方式
函数声明
1 2 3 4 5 6 7 8 9
| function customRef<T>(factory: CustomRefFactory<T>): Ref<T>
type CustomRefFactory<T> = ( track: () => void, trigger: () => void ) => { get: () => T set: (value: T) => void }
|
customRef
接收一个 factory 函数,返回一个 ref 数据
- factory 函数接收 track 和 trigger 两个函数作为参数,返回一个带有 get 方法和 set 方法的对象
防抖 ref 实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import { customRef } from 'vue'
export function useDebouncedRef(value: string, delay: number = 200) { let timeout: number return customRef((track, trigger) => { return { get() { track() return value }, set(newValue) { clearTimeout(timeout) timeout = setTimeout(() => { value = newValue trigger() }, delay) } } }) }
|
Teleport
用于改变组件模板内容的实际 DOM 渲染位置,而不改变组件的逻辑关系,可用于实现模态框等效果
e.g. 实现一个模态框
一个 outer 块中包含 MyModal 组件,在逻辑上为父子关系
1 2 3 4 5 6
| <div class="outer"> <h3>Tooltips with Vue 3 Teleport</h3> <div> <MyModal /> </div> </div>
|
在编写 css 布局时,通常将模态框显示在整个视窗的中间,但由于父子关系,outer 块的布局可能会导致 MyModal 的定位出现问题,MyModal 的 DOM 位置应该脱离 outer 块,因此使用 Teleport 实现 MyModal,改变实际 DOM 位置
1 2 3 4 5 6 7 8 9
| <button @click="open = true">Open Modal</button>
<Teleport to="body"> <div v-if="open" class="modal"> <p>Hello from the modal!</p> <button @click="open = false">Close</button> </div> </Teleport>
|